From df152d59053c742f35656573091fd3e6d8cbbb0f Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 2 Jun 2014 00:58:04 +0200 Subject: [PATCH 001/269] implementations of hpack integers and huffman decoding --- jetty-hpack/pom.xml | 78 ++++ .../java/org/eclipse/jetty/hpack/Huffman.java | 392 ++++++++++++++++++ .../org/eclipse/jetty/hpack/NBitInteger.java | 159 +++++++ .../org/eclipse/jetty/hpack/HuffmanTest.java | 37 ++ .../eclipse/jetty/hpack/NBitIntegerTest.java | 94 +++++ jetty-http2/pom.xml | 78 ++++ 6 files changed, 838 insertions(+) create mode 100644 jetty-hpack/pom.xml create mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java create mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java create mode 100644 jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java create mode 100644 jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java create mode 100644 jetty-http2/pom.xml diff --git a/jetty-hpack/pom.xml b/jetty-hpack/pom.xml new file mode 100644 index 00000000000..ecb70b102a9 --- /dev/null +++ b/jetty-hpack/pom.xml @@ -0,0 +1,78 @@ + + + + jetty-project + org.eclipse.jetty + 9.2.0-SNAPSHOT + + 4.0.0 + jetty-hpack + Jetty :: HPACK Utility + http://www.eclipse.org/jetty + + ${project.groupId}.http + + + + org.eclipse.jetty + jetty-util + ${project.version} + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + manifest + + + + javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,* + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + artifact-jar + + jar + + + + test-jar + + test-jar + + + + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + org.codehaus.mojo + findbugs-maven-plugin + + org.eclipse.jetty.http.* + + + + + diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java new file mode 100644 index 00000000000..8ad140288b7 --- /dev/null +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java @@ -0,0 +1,392 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.hpack; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class Huffman +{ + + // Appendix C: Huffman Codes + // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C + static final int[][] CODES = + { + /* ( 0) |11111111|11111111|11101110|10 */ {0x3ffffba,26}, + /* ( 1) |11111111|11111111|11101110|11 */ {0x3ffffbb,26}, + /* ( 2) |11111111|11111111|11101111|00 */ {0x3ffffbc,26}, + /* ( 3) |11111111|11111111|11101111|01 */ {0x3ffffbd,26}, + /* ( 4) |11111111|11111111|11101111|10 */ {0x3ffffbe,26}, + /* ( 5) |11111111|11111111|11101111|11 */ {0x3ffffbf,26}, + /* ( 6) |11111111|11111111|11110000|00 */ {0x3ffffc0,26}, + /* ( 7) |11111111|11111111|11110000|01 */ {0x3ffffc1,26}, + /* ( 8) |11111111|11111111|11110000|10 */ {0x3ffffc2,26}, + /* ( 9) |11111111|11111111|11110000|11 */ {0x3ffffc3,26}, + /* ( 10) |11111111|11111111|11110001|00 */ {0x3ffffc4,26}, + /* ( 11) |11111111|11111111|11110001|01 */ {0x3ffffc5,26}, + /* ( 12) |11111111|11111111|11110001|10 */ {0x3ffffc6,26}, + /* ( 13) |11111111|11111111|11110001|11 */ {0x3ffffc7,26}, + /* ( 14) |11111111|11111111|11110010|00 */ {0x3ffffc8,26}, + /* ( 15) |11111111|11111111|11110010|01 */ {0x3ffffc9,26}, + /* ( 16) |11111111|11111111|11110010|10 */ {0x3ffffca,26}, + /* ( 17) |11111111|11111111|11110010|11 */ {0x3ffffcb,26}, + /* ( 18) |11111111|11111111|11110011|00 */ {0x3ffffcc,26}, + /* ( 19) |11111111|11111111|11110011|01 */ {0x3ffffcd,26}, + /* ( 20) |11111111|11111111|11110011|10 */ {0x3ffffce,26}, + /* ( 21) |11111111|11111111|11110011|11 */ {0x3ffffcf,26}, + /* ( 22) |11111111|11111111|11110100|00 */ {0x3ffffd0,26}, + /* ( 23) |11111111|11111111|11110100|01 */ {0x3ffffd1,26}, + /* ( 24) |11111111|11111111|11110100|10 */ {0x3ffffd2,26}, + /* ( 25) |11111111|11111111|11110100|11 */ {0x3ffffd3,26}, + /* ( 26) |11111111|11111111|11110101|00 */ {0x3ffffd4,26}, + /* ( 27) |11111111|11111111|11110101|01 */ {0x3ffffd5,26}, + /* ( 28) |11111111|11111111|11110101|10 */ {0x3ffffd6,26}, + /* ( 29) |11111111|11111111|11110101|11 */ {0x3ffffd7,26}, + /* ( 30) |11111111|11111111|11110110|00 */ {0x3ffffd8,26}, + /* ( 31) |11111111|11111111|11110110|01 */ {0x3ffffd9,26}, + /*' ' ( 32) |00110 */ {0x6, 5}, + /*'!' ( 33) |11111111|11100 */ {0x1ffc,13}, + /*'"' ( 34) |11111000|0 */ {0x1f0, 9}, + /*'#' ( 35) |11111111|111100 */ {0x3ffc,14}, + /*'$' ( 36) |11111111|1111100 */ {0x7ffc,15}, + /*'%' ( 37) |011110 */ {0x1e, 6}, + /*'&' ( 38) |1100100 */ {0x64, 7}, + /*''' ( 39) |11111111|11101 */ {0x1ffd,13}, + /*'(' ( 40) |11111110|10 */ {0x3fa,10}, + /*')' ( 41) |11111000|1 */ {0x1f1, 9}, + /*'*' ( 42) |11111110|11 */ {0x3fb,10}, + /*'+' ( 43) |11111111|00 */ {0x3fc,10}, + /*',' ( 44) |1100101 */ {0x65, 7}, + /*'-' ( 45) |1100110 */ {0x66, 7}, + /*'.' ( 46) |011111 */ {0x1f, 6}, + /*'/' ( 47) |00111 */ {0x7, 5}, + /*'0' ( 48) |0000 */ {0x0, 4}, + /*'1' ( 49) |0001 */ {0x1, 4}, + /*'2' ( 50) |0010 */ {0x2, 4}, + /*'3' ( 51) |01000 */ {0x8, 5}, + /*'4' ( 52) |100000 */ {0x20, 6}, + /*'5' ( 53) |100001 */ {0x21, 6}, + /*'6' ( 54) |100010 */ {0x22, 6}, + /*'7' ( 55) |100011 */ {0x23, 6}, + /*'8' ( 56) |100100 */ {0x24, 6}, + /*'9' ( 57) |100101 */ {0x25, 6}, + /*':' ( 58) |100110 */ {0x26, 6}, + /*';' ( 59) |11101100| */ {0xec, 8}, + /*'<' ( 60) |11111111|11111110|0 */ {0x1fffc,17}, + /*'=' ( 61) |100111 */ {0x27, 6}, + /*'>' ( 62) |11111111|1111101 */ {0x7ffd,15}, + /*'?' ( 63) |11111111|01 */ {0x3fd,10}, + /*'@' ( 64) |11111111|1111110 */ {0x7ffe,15}, + /*'A' ( 65) |1100111 */ {0x67, 7}, + /*'B' ( 66) |11101101| */ {0xed, 8}, + /*'C' ( 67) |11101110| */ {0xee, 8}, + /*'D' ( 68) |1101000 */ {0x68, 7}, + /*'E' ( 69) |11101111| */ {0xef, 8}, + /*'F' ( 70) |1101001 */ {0x69, 7}, + /*'G' ( 71) |1101010 */ {0x6a, 7}, + /*'H' ( 72) |11111001|0 */ {0x1f2, 9}, + /*'I' ( 73) |11110000| */ {0xf0, 8}, + /*'J' ( 74) |11111001|1 */ {0x1f3, 9}, + /*'K' ( 75) |11111010|0 */ {0x1f4, 9}, + /*'L' ( 76) |11111010|1 */ {0x1f5, 9}, + /*'M' ( 77) |1101011 */ {0x6b, 7}, + /*'N' ( 78) |1101100 */ {0x6c, 7}, + /*'O' ( 79) |11110001| */ {0xf1, 8}, + /*'P' ( 80) |11110010| */ {0xf2, 8}, + /*'Q' ( 81) |11111011|0 */ {0x1f6, 9}, + /*'R' ( 82) |11111011|1 */ {0x1f7, 9}, + /*'S' ( 83) |1101101 */ {0x6d, 7}, + /*'T' ( 84) |101000 */ {0x28, 6}, + /*'U' ( 85) |11110011| */ {0xf3, 8}, + /*'V' ( 86) |11111100|0 */ {0x1f8, 9}, + /*'W' ( 87) |11111100|1 */ {0x1f9, 9}, + /*'X' ( 88) |11110100| */ {0xf4, 8}, + /*'Y' ( 89) |11111101|0 */ {0x1fa, 9}, + /*'Z' ( 90) |11111101|1 */ {0x1fb, 9}, + /*'[' ( 91) |11111111|100 */ {0x7fc,11}, + /*'\' ( 92) |11111111|11111111|11110110|10 */ {0x3ffffda,26}, + /*']' ( 93) |11111111|101 */ {0x7fd,11}, + /*'^' ( 94) |11111111|111101 */ {0x3ffd,14}, + /*'_' ( 95) |1101110 */ {0x6e, 7}, + /*'`' ( 96) |11111111|11111111|10 */ {0x3fffe,18}, + /*'a' ( 97) |01001 */ {0x9, 5}, + /*'b' ( 98) |1101111 */ {0x6f, 7}, + /*'c' ( 99) |01010 */ {0xa, 5}, + /*'d' (100) |101001 */ {0x29, 6}, + /*'e' (101) |01011 */ {0xb, 5}, + /*'f' (102) |1110000 */ {0x70, 7}, + /*'g' (103) |101010 */ {0x2a, 6}, + /*'h' (104) |101011 */ {0x2b, 6}, + /*'i' (105) |01100 */ {0xc, 5}, + /*'j' (106) |11110101| */ {0xf5, 8}, + /*'k' (107) |11110110| */ {0xf6, 8}, + /*'l' (108) |101100 */ {0x2c, 6}, + /*'m' (109) |101101 */ {0x2d, 6}, + /*'n' (110) |101110 */ {0x2e, 6}, + /*'o' (111) |01101 */ {0xd, 5}, + /*'p' (112) |101111 */ {0x2f, 6}, + /*'q' (113) |11111110|0 */ {0x1fc, 9}, + /*'r' (114) |110000 */ {0x30, 6}, + /*'s' (115) |110001 */ {0x31, 6}, + /*'t' (116) |01110 */ {0xe, 5}, + /*'u' (117) |1110001 */ {0x71, 7}, + /*'v' (118) |1110010 */ {0x72, 7}, + /*'w' (119) |1110011 */ {0x73, 7}, + /*'x' (120) |1110100 */ {0x74, 7}, + /*'y' (121) |1110101 */ {0x75, 7}, + /*'z' (122) |11110111| */ {0xf7, 8}, + /*'{' (123) |11111111|11111110|1 */ {0x1fffd,17}, + /*'|' (124) |11111111|1100 */ {0xffc,12}, + /*'}' (125) |11111111|11111111|0 */ {0x1fffe,17}, + /*'~' (126) |11111111|1101 */ {0xffd,12}, + /* (127) |11111111|11111111|11110110|11 */ {0x3ffffdb,26}, + /* (128) |11111111|11111111|11110111|00 */ {0x3ffffdc,26}, + /* (129) |11111111|11111111|11110111|01 */ {0x3ffffdd,26}, + /* (130) |11111111|11111111|11110111|10 */ {0x3ffffde,26}, + /* (131) |11111111|11111111|11110111|11 */ {0x3ffffdf,26}, + /* (132) |11111111|11111111|11111000|00 */ {0x3ffffe0,26}, + /* (133) |11111111|11111111|11111000|01 */ {0x3ffffe1,26}, + /* (134) |11111111|11111111|11111000|10 */ {0x3ffffe2,26}, + /* (135) |11111111|11111111|11111000|11 */ {0x3ffffe3,26}, + /* (136) |11111111|11111111|11111001|00 */ {0x3ffffe4,26}, + /* (137) |11111111|11111111|11111001|01 */ {0x3ffffe5,26}, + /* (138) |11111111|11111111|11111001|10 */ {0x3ffffe6,26}, + /* (139) |11111111|11111111|11111001|11 */ {0x3ffffe7,26}, + /* (140) |11111111|11111111|11111010|00 */ {0x3ffffe8,26}, + /* (141) |11111111|11111111|11111010|01 */ {0x3ffffe9,26}, + /* (142) |11111111|11111111|11111010|10 */ {0x3ffffea,26}, + /* (143) |11111111|11111111|11111010|11 */ {0x3ffffeb,26}, + /* (144) |11111111|11111111|11111011|00 */ {0x3ffffec,26}, + /* (145) |11111111|11111111|11111011|01 */ {0x3ffffed,26}, + /* (146) |11111111|11111111|11111011|10 */ {0x3ffffee,26}, + /* (147) |11111111|11111111|11111011|11 */ {0x3ffffef,26}, + /* (148) |11111111|11111111|11111100|00 */ {0x3fffff0,26}, + /* (149) |11111111|11111111|11111100|01 */ {0x3fffff1,26}, + /* (150) |11111111|11111111|11111100|10 */ {0x3fffff2,26}, + /* (151) |11111111|11111111|11111100|11 */ {0x3fffff3,26}, + /* (152) |11111111|11111111|11111101|00 */ {0x3fffff4,26}, + /* (153) |11111111|11111111|11111101|01 */ {0x3fffff5,26}, + /* (154) |11111111|11111111|11111101|10 */ {0x3fffff6,26}, + /* (155) |11111111|11111111|11111101|11 */ {0x3fffff7,26}, + /* (156) |11111111|11111111|11111110|00 */ {0x3fffff8,26}, + /* (157) |11111111|11111111|11111110|01 */ {0x3fffff9,26}, + /* (158) |11111111|11111111|11111110|10 */ {0x3fffffa,26}, + /* (159) |11111111|11111111|11111110|11 */ {0x3fffffb,26}, + /* (160) |11111111|11111111|11111111|00 */ {0x3fffffc,26}, + /* (161) |11111111|11111111|11111111|01 */ {0x3fffffd,26}, + /* (162) |11111111|11111111|11111111|10 */ {0x3fffffe,26}, + /* (163) |11111111|11111111|11111111|11 */ {0x3ffffff,26}, + /* (164) |11111111|11111111|11000000|0 */ {0x1ffff80,25}, + /* (165) |11111111|11111111|11000000|1 */ {0x1ffff81,25}, + /* (166) |11111111|11111111|11000001|0 */ {0x1ffff82,25}, + /* (167) |11111111|11111111|11000001|1 */ {0x1ffff83,25}, + /* (168) |11111111|11111111|11000010|0 */ {0x1ffff84,25}, + /* (169) |11111111|11111111|11000010|1 */ {0x1ffff85,25}, + /* (170) |11111111|11111111|11000011|0 */ {0x1ffff86,25}, + /* (171) |11111111|11111111|11000011|1 */ {0x1ffff87,25}, + /* (172) |11111111|11111111|11000100|0 */ {0x1ffff88,25}, + /* (173) |11111111|11111111|11000100|1 */ {0x1ffff89,25}, + /* (174) |11111111|11111111|11000101|0 */ {0x1ffff8a,25}, + /* (175) |11111111|11111111|11000101|1 */ {0x1ffff8b,25}, + /* (176) |11111111|11111111|11000110|0 */ {0x1ffff8c,25}, + /* (177) |11111111|11111111|11000110|1 */ {0x1ffff8d,25}, + /* (178) |11111111|11111111|11000111|0 */ {0x1ffff8e,25}, + /* (179) |11111111|11111111|11000111|1 */ {0x1ffff8f,25}, + /* (180) |11111111|11111111|11001000|0 */ {0x1ffff90,25}, + /* (181) |11111111|11111111|11001000|1 */ {0x1ffff91,25}, + /* (182) |11111111|11111111|11001001|0 */ {0x1ffff92,25}, + /* (183) |11111111|11111111|11001001|1 */ {0x1ffff93,25}, + /* (184) |11111111|11111111|11001010|0 */ {0x1ffff94,25}, + /* (185) |11111111|11111111|11001010|1 */ {0x1ffff95,25}, + /* (186) |11111111|11111111|11001011|0 */ {0x1ffff96,25}, + /* (187) |11111111|11111111|11001011|1 */ {0x1ffff97,25}, + /* (188) |11111111|11111111|11001100|0 */ {0x1ffff98,25}, + /* (189) |11111111|11111111|11001100|1 */ {0x1ffff99,25}, + /* (190) |11111111|11111111|11001101|0 */ {0x1ffff9a,25}, + /* (191) |11111111|11111111|11001101|1 */ {0x1ffff9b,25}, + /* (192) |11111111|11111111|11001110|0 */ {0x1ffff9c,25}, + /* (193) |11111111|11111111|11001110|1 */ {0x1ffff9d,25}, + /* (194) |11111111|11111111|11001111|0 */ {0x1ffff9e,25}, + /* (195) |11111111|11111111|11001111|1 */ {0x1ffff9f,25}, + /* (196) |11111111|11111111|11010000|0 */ {0x1ffffa0,25}, + /* (197) |11111111|11111111|11010000|1 */ {0x1ffffa1,25}, + /* (198) |11111111|11111111|11010001|0 */ {0x1ffffa2,25}, + /* (199) |11111111|11111111|11010001|1 */ {0x1ffffa3,25}, + /* (200) |11111111|11111111|11010010|0 */ {0x1ffffa4,25}, + /* (201) |11111111|11111111|11010010|1 */ {0x1ffffa5,25}, + /* (202) |11111111|11111111|11010011|0 */ {0x1ffffa6,25}, + /* (203) |11111111|11111111|11010011|1 */ {0x1ffffa7,25}, + /* (204) |11111111|11111111|11010100|0 */ {0x1ffffa8,25}, + /* (205) |11111111|11111111|11010100|1 */ {0x1ffffa9,25}, + /* (206) |11111111|11111111|11010101|0 */ {0x1ffffaa,25}, + /* (207) |11111111|11111111|11010101|1 */ {0x1ffffab,25}, + /* (208) |11111111|11111111|11010110|0 */ {0x1ffffac,25}, + /* (209) |11111111|11111111|11010110|1 */ {0x1ffffad,25}, + /* (210) |11111111|11111111|11010111|0 */ {0x1ffffae,25}, + /* (211) |11111111|11111111|11010111|1 */ {0x1ffffaf,25}, + /* (212) |11111111|11111111|11011000|0 */ {0x1ffffb0,25}, + /* (213) |11111111|11111111|11011000|1 */ {0x1ffffb1,25}, + /* (214) |11111111|11111111|11011001|0 */ {0x1ffffb2,25}, + /* (215) |11111111|11111111|11011001|1 */ {0x1ffffb3,25}, + /* (216) |11111111|11111111|11011010|0 */ {0x1ffffb4,25}, + /* (217) |11111111|11111111|11011010|1 */ {0x1ffffb5,25}, + /* (218) |11111111|11111111|11011011|0 */ {0x1ffffb6,25}, + /* (219) |11111111|11111111|11011011|1 */ {0x1ffffb7,25}, + /* (220) |11111111|11111111|11011100|0 */ {0x1ffffb8,25}, + /* (221) |11111111|11111111|11011100|1 */ {0x1ffffb9,25}, + /* (222) |11111111|11111111|11011101|0 */ {0x1ffffba,25}, + /* (223) |11111111|11111111|11011101|1 */ {0x1ffffbb,25}, + /* (224) |11111111|11111111|11011110|0 */ {0x1ffffbc,25}, + /* (225) |11111111|11111111|11011110|1 */ {0x1ffffbd,25}, + /* (226) |11111111|11111111|11011111|0 */ {0x1ffffbe,25}, + /* (227) |11111111|11111111|11011111|1 */ {0x1ffffbf,25}, + /* (228) |11111111|11111111|11100000|0 */ {0x1ffffc0,25}, + /* (229) |11111111|11111111|11100000|1 */ {0x1ffffc1,25}, + /* (230) |11111111|11111111|11100001|0 */ {0x1ffffc2,25}, + /* (231) |11111111|11111111|11100001|1 */ {0x1ffffc3,25}, + /* (232) |11111111|11111111|11100010|0 */ {0x1ffffc4,25}, + /* (233) |11111111|11111111|11100010|1 */ {0x1ffffc5,25}, + /* (234) |11111111|11111111|11100011|0 */ {0x1ffffc6,25}, + /* (235) |11111111|11111111|11100011|1 */ {0x1ffffc7,25}, + /* (236) |11111111|11111111|11100100|0 */ {0x1ffffc8,25}, + /* (237) |11111111|11111111|11100100|1 */ {0x1ffffc9,25}, + /* (238) |11111111|11111111|11100101|0 */ {0x1ffffca,25}, + /* (239) |11111111|11111111|11100101|1 */ {0x1ffffcb,25}, + /* (240) |11111111|11111111|11100110|0 */ {0x1ffffcc,25}, + /* (241) |11111111|11111111|11100110|1 */ {0x1ffffcd,25}, + /* (242) |11111111|11111111|11100111|0 */ {0x1ffffce,25}, + /* (243) |11111111|11111111|11100111|1 */ {0x1ffffcf,25}, + /* (244) |11111111|11111111|11101000|0 */ {0x1ffffd0,25}, + /* (245) |11111111|11111111|11101000|1 */ {0x1ffffd1,25}, + /* (246) |11111111|11111111|11101001|0 */ {0x1ffffd2,25}, + /* (247) |11111111|11111111|11101001|1 */ {0x1ffffd3,25}, + /* (248) |11111111|11111111|11101010|0 */ {0x1ffffd4,25}, + /* (249) |11111111|11111111|11101010|1 */ {0x1ffffd5,25}, + /* (250) |11111111|11111111|11101011|0 */ {0x1ffffd6,25}, + /* (251) |11111111|11111111|11101011|1 */ {0x1ffffd7,25}, + /* (252) |11111111|11111111|11101100|0 */ {0x1ffffd8,25}, + /* (253) |11111111|11111111|11101100|1 */ {0x1ffffd9,25}, + /* (254) |11111111|11111111|11101101|0 */ {0x1ffffda,25}, + /* (255) |11111111|11111111|11101101|1 */ {0x1ffffdb,25}, + /* (256) |11111111|11111111|11101110|0 */ {0x1ffffdc,25}, + + }; + + // Huffman decode tree stored in a flattened char array for good + // locality of reference. + static final char[] tree; + static final byte[] rowsym; + static final byte[] rowbits; + + static + { + int r=0; + for (int i=0;i 8) + { + len -= 8; + int i = ((code >>> len) & 0xFF); + if (rowbits[current]!=0) + throw new IllegalStateException("invalid dictionary: prefix not unique"); + + int t=current*256+i; + current = tree[t]; + if (current == 0) + { + tree[t] = (char)++r; + current=r; + } + } + + int terminal = ++r; + rowsym[r]=(byte)sym; + int b = len & 0x07; + int terminalBits = b == 0?8:b; + + rowbits[r]=(byte)terminalBits; + int shift = 8 - len; + int start = current*256 + ((code << shift) & 0xFF); + int end = start + (1<= 8) + { + int c = (current >>> (bits - 8)) & 0xFF; + node = tree[node*256+c]; + if (rowbits[node]!=0) + { + // terminal node + baos.write(rowsym[node]); + bits -= rowbits[node]; + node = 0; + } + else + { + // non-terminal node + bits -= 8; + } + } + } + + while (bits > 0) + { + int c = (current << (8 - bits)) & 0xFF; + node = tree[node*256+c]; + if (rowbits[node]==0 || rowbits[node] > bits) + break; + + if (rowbits[node]==0) + throw new IllegalStateException(); + + baos.write(rowsym[node]); + bits -= rowbits[node]; + node = 0; + } + + return baos.toByteArray(); + } +} diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java new file mode 100644 index 00000000000..86f922cb521 --- /dev/null +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java @@ -0,0 +1,159 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.hpack; + +import java.nio.ByteBuffer; + +public class NBitInteger +{ + public static void encode3(ByteBuffer buf, int n, int i) + { + int p=buf.position()-1; + + int nbits = 0xFF >>> (8 - 3); + + if (i < nbits) + { + buf.put(p,(byte)((buf.get(p)&~nbits)|i)); + } + else + { + buf.put(p,(byte)(buf.get(p)|nbits)); + + int length = i - nbits; + while (true) + { + if ((length & ~0x7F) == 0) + { + buf.put((byte)length); + return; + } + else + { + buf.put((byte)((length & 0x7F) | 0x80)); + length >>>= 7; + } + } + } + } + + + public static void encode5(ByteBuffer buf, int i) + { + int p=buf.position()-1; + int nbits = 0xFF >>> (8 - 5); + + if (i < nbits) + { + buf.put(p,(byte)((buf.get(p)&~nbits)|i)); + } + else + { + buf.put(p,(byte)(buf.get(p)|nbits)); + + int length = i - nbits; + while (true) + { + if ((length & ~0x7F) == 0) + { + buf.put((byte)length); + return; + } + else + { + buf.put((byte)((length & 0x7F) | 0x80)); + length >>>= 7; + } + } + } + } + + + public static void encode8(ByteBuffer buf, int i) + { + int nbits = 0xFF; + + if (i < nbits) + { + buf.put((byte)i); + } + else + { + buf.put((byte)nbits); + + int length = i - nbits; + while (true) + { + if ((length & ~0x7F) == 0) + { + buf.put((byte)length); + return; + } + else + { + buf.put((byte)((length & 0x7F) | 0x80)); + length >>>= 7; + } + } + } + } + + public static int dencode5(ByteBuffer buf) + { + int nbits = 0xFF >>> (8 - 5); + + int i=buf.get(buf.position()-1)&nbits; + + if (i == nbits) + { + int m=1; + int b; + do + { + b = 0xff&buf.get(); + i = i + (b&127) * m; + m = m*128; + } + while ((b&128) == 128); + } + return i; + } + + public static int dencode8(ByteBuffer buf) + { + int nbits = 0xFF >>> (8 - 8); + + int i=buf.get()&nbits; + + if (i == nbits) + { + int m=1; + int b; + do + { + b = 0xff&buf.get(); + i = i + (b&127) * m; + m = m*128; + } + while ((b&128) == 128); + } + return i; + } + +} diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java new file mode 100644 index 00000000000..6059ce1794e --- /dev/null +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java @@ -0,0 +1,37 @@ +package org.eclipse.jetty.hpack; + +import org.junit.Assert; + +import org.eclipse.jetty.util.TypeUtil; +import org.junit.Test; + +public class HuffmanTest +{ + + String[][] tests = + { + {"D.4.1","e7cf9bebe89b6fb16fa9b6ff","www.example.com"}, + {"D.4.2","b9b9949556bf","no-cache"}, + {"D.4.3k","571c5cdb737b2faf","custom-key"}, + {"D.4.3v","571c5cdb73724d9c57","custom-value"}, + {"D.6.1d","d6dbb29884de2a718805062098513109b56ba3","Mon, 21 Oct 2013 20:13:21 GMT"}, + {"D.6.1l","adcebf198e7e7cf9bebe89b6fb16fa9b6f","https://www.example.com"}, + {"D.6.2te","abdd97ff","gzip"}, + {"D.4.2cookie","e0d6cf9f6e8f9fd3e5f6fa76fefd3c7edf9eff1f2f0f3cfe9f6fcf7f8f879f61ad4f4cc9a973a2200ec3725e18b1b74e3f","foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"}, + {"D.6.2date","d6dbb29884de2a718805062098513111b56ba3","Mon, 21 Oct 2013 20:13:22 GMT"}, + }; + + @Test + public void testDecode() throws Exception + { + for (String[] test:tests) + { + byte[] encoded=TypeUtil.fromHexString(test[1]); + byte[] decoded=Huffman.decode(encoded); + + String d=new String(decoded); + Assert.assertEquals(test[0],test[2],d); + } + + } +} diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java new file mode 100644 index 00000000000..9039d901f40 --- /dev/null +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java @@ -0,0 +1,94 @@ +package org.eclipse.jetty.hpack; + +import static org.junit.Assert.*; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.TypeUtil; +import org.junit.Assert; +import org.junit.Test; + +public class NBitIntegerTest +{ + + @Test + public void testEncodeExampleD_1_1() + { + ByteBuffer buf = BufferUtil.allocate(16); + int p=BufferUtil.flipToFill(buf); + buf.put((byte)0x77); + buf.put((byte)0xFF); + NBitInteger.encode5(buf,10); + BufferUtil.flipToFlush(buf,p); + + String r=TypeUtil.toHexString(BufferUtil.toArray(buf)); + + Assert.assertEquals("77Ea",r); + + } + + @Test + public void testDecodeExampleD_1_1() + { + ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF")); + buf.position(2); + + Assert.assertEquals(10,NBitInteger.dencode5(buf)); + } + + + @Test + public void testEncodeExampleD_1_2() + { + ByteBuffer buf = BufferUtil.allocate(16); + int p=BufferUtil.flipToFill(buf); + buf.put((byte)0x88); + buf.put((byte)0x00); + NBitInteger.encode5(buf,1337); + BufferUtil.flipToFlush(buf,p); + + String r=TypeUtil.toHexString(BufferUtil.toArray(buf)); + + Assert.assertEquals("881f9a0a",r); + + } + + @Test + public void testDecodeExampleD_1_2() + { + ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff")); + buf.position(2); + + Assert.assertEquals(1337,NBitInteger.dencode5(buf)); + } + + + @Test + public void testEncodeExampleD_1_3() + { + ByteBuffer buf = BufferUtil.allocate(16); + int p=BufferUtil.flipToFill(buf); + buf.put((byte)0x88); + buf.put((byte)0xFF); + NBitInteger.encode8(buf,42); + BufferUtil.flipToFlush(buf,p); + + String r=TypeUtil.toHexString(BufferUtil.toArray(buf)); + + Assert.assertEquals("88Ff2a",r); + + } + + + @Test + public void testDecodeExampleD_1_3() + { + ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf")); + buf.position(1); + + Assert.assertEquals(42,NBitInteger.dencode8(buf)); + } + + +} diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml new file mode 100644 index 00000000000..7dfa284b525 --- /dev/null +++ b/jetty-http2/pom.xml @@ -0,0 +1,78 @@ + + + + jetty-project + org.eclipse.jetty + 9.2.0-SNAPSHOT + + 4.0.0 + jetty-http2 + Jetty :: Http2 Utility + http://www.eclipse.org/jetty + + ${project.groupId}.http + + + + org.eclipse.jetty + jetty-util + ${project.version} + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + manifest + + + + javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,* + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + artifact-jar + + jar + + + + test-jar + + test-jar + + + + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + org.codehaus.mojo + findbugs-maven-plugin + + org.eclipse.jetty.http.* + + + + + From ad26b2756482a759f0c789adc141be182675d367 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 2 Jun 2014 01:04:23 +0200 Subject: [PATCH 002/269] added licence headers --- .../org/eclipse/jetty/hpack/HuffmanTest.java | 18 ++++++++++++++++++ .../eclipse/jetty/hpack/NBitIntegerTest.java | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java index 6059ce1794e..87426c6ce65 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java @@ -1,3 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + package org.eclipse.jetty.hpack; import org.junit.Assert; diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java index 9039d901f40..a58bdec59b6 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java @@ -1,3 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + package org.eclipse.jetty.hpack; import static org.junit.Assert.*; From 76724d8dfd967b4cd2db203f66826f00125857af Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 2 Jun 2014 01:25:08 +0200 Subject: [PATCH 003/269] use buffers --- .../java/org/eclipse/jetty/hpack/Huffman.java | 26 ++++++++++--------- .../org/eclipse/jetty/hpack/HuffmanTest.java | 9 +++---- .../eclipse/jetty/hpack/NBitIntegerTest.java | 2 -- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java index 8ad140288b7..11521fde5b8 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java @@ -18,8 +18,8 @@ package org.eclipse.jetty.hpack; -import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.ByteBuffer; public class Huffman { @@ -284,14 +284,14 @@ public class Huffman /* (253) |11111111|11111111|11101100|1 */ {0x1ffffd9,25}, /* (254) |11111111|11111111|11101101|0 */ {0x1ffffda,25}, /* (255) |11111111|11111111|11101101|1 */ {0x1ffffdb,25}, - /* (256) |11111111|11111111|11101110|0 */ {0x1ffffdc,25}, + /*EOS (256) |11111111|11111111|11101110|0 */ {0x1ffffdc,25}, }; // Huffman decode tree stored in a flattened char array for good // locality of reference. static final char[] tree; - static final byte[] rowsym; + static final char[] rowsym; static final byte[] rowbits; static @@ -300,7 +300,7 @@ public class Huffman for (int i=0;i= 8) @@ -360,7 +362,7 @@ public class Huffman if (rowbits[node]!=0) { // terminal node - baos.write(rowsym[node]); + out.append(rowsym[node]); bits -= rowbits[node]; node = 0; } @@ -382,11 +384,11 @@ public class Huffman if (rowbits[node]==0) throw new IllegalStateException(); - baos.write(rowsym[node]); + out.append(rowsym[node]); bits -= rowbits[node]; node = 0; } - return baos.toByteArray(); + return out.toString(); } } diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java index 87426c6ce65..2ccd800898f 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java @@ -18,8 +18,9 @@ package org.eclipse.jetty.hpack; -import org.junit.Assert; +import java.nio.ByteBuffer; +import org.junit.Assert; import org.eclipse.jetty.util.TypeUtil; import org.junit.Test; @@ -45,10 +46,8 @@ public class HuffmanTest for (String[] test:tests) { byte[] encoded=TypeUtil.fromHexString(test[1]); - byte[] decoded=Huffman.decode(encoded); - - String d=new String(decoded); - Assert.assertEquals(test[0],test[2],d); + String decoded=Huffman.decode(ByteBuffer.wrap(encoded)); + Assert.assertEquals(test[0],test[2],decoded); } } diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java index a58bdec59b6..d8e726d76a6 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java @@ -18,8 +18,6 @@ package org.eclipse.jetty.hpack; -import static org.junit.Assert.*; - import java.nio.ByteBuffer; import org.eclipse.jetty.util.BufferUtil; From 48f1668b287532cf6145d8dfaaab7221991813fc Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 2 Jun 2014 11:55:43 +0200 Subject: [PATCH 004/269] implement huffman encoding --- .../java/org/eclipse/jetty/hpack/Huffman.java | 36 +++++++++++++++++++ .../org/eclipse/jetty/hpack/NBitInteger.java | 4 +-- .../org/eclipse/jetty/hpack/HuffmanTest.java | 17 ++++++++- .../eclipse/jetty/hpack/NBitIntegerTest.java | 6 ++-- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java index 11521fde5b8..b16bdf8cb5b 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java @@ -344,6 +344,8 @@ public class Huffman static public String decode(ByteBuffer buf) throws IOException { + // TODO offer a version that does a direct lookup of compressed strings to known values + StringBuilder out = new StringBuilder(buf.remaining()*2); int node = 0; int current = 0; @@ -391,4 +393,38 @@ public class Huffman return out.toString(); } + + + static public void encode(ByteBuffer buf,String s) throws IOException + { + long current = 0; + int n = 0; + + int len = s.length(); + for (int i=0;i=128) + throw new IllegalArgumentException(); + int code = CODES[c][0]; + int bits = CODES[c][1]; + + current <<= bits; + current |= code; + n += bits; + + while (n >= 8) + { + n -= 8; + buf.put((byte)(current >> n)); + } + } + + if (n > 0) + { + current <<= (8 - n); + current |= (0xFF >>> n); + buf.put((byte)current); + } + } } diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java index 86f922cb521..692a64542c1 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java @@ -114,7 +114,7 @@ public class NBitInteger } } - public static int dencode5(ByteBuffer buf) + public static int decode5(ByteBuffer buf) { int nbits = 0xFF >>> (8 - 5); @@ -135,7 +135,7 @@ public class NBitInteger return i; } - public static int dencode8(ByteBuffer buf) + public static int decode8(ByteBuffer buf) { int nbits = 0xFF >>> (8 - 8); diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java index 2ccd800898f..a68b16f2ebf 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java @@ -21,12 +21,12 @@ package org.eclipse.jetty.hpack; import java.nio.ByteBuffer; import org.junit.Assert; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; import org.junit.Test; public class HuffmanTest { - String[][] tests = { {"D.4.1","e7cf9bebe89b6fb16fa9b6ff","www.example.com"}, @@ -49,6 +49,21 @@ public class HuffmanTest String decoded=Huffman.decode(ByteBuffer.wrap(encoded)); Assert.assertEquals(test[0],test[2],decoded); } + } + + @Test + public void testEncode() throws Exception + { + for (String[] test:tests) + { + ByteBuffer buf = BufferUtil.allocate(1024); + int pos=BufferUtil.flipToFill(buf); + Huffman.encode(buf,test[2]); + BufferUtil.flipToFlush(buf,pos); + String encoded=TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase(); + Assert.assertEquals(test[0],test[1],encoded); + } } + } diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java index d8e726d76a6..36900e31659 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java @@ -50,7 +50,7 @@ public class NBitIntegerTest ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF")); buf.position(2); - Assert.assertEquals(10,NBitInteger.dencode5(buf)); + Assert.assertEquals(10,NBitInteger.decode5(buf)); } @@ -76,7 +76,7 @@ public class NBitIntegerTest ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff")); buf.position(2); - Assert.assertEquals(1337,NBitInteger.dencode5(buf)); + Assert.assertEquals(1337,NBitInteger.decode5(buf)); } @@ -103,7 +103,7 @@ public class NBitIntegerTest ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf")); buf.position(1); - Assert.assertEquals(42,NBitInteger.dencode8(buf)); + Assert.assertEquals(42,NBitInteger.decode8(buf)); } From c607bb6efc9374a3b34d0af67f9daa7b10eb6457 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 2 Jun 2014 13:03:48 +0200 Subject: [PATCH 005/269] use bytebuffer array --- .../java/org/eclipse/jetty/hpack/Huffman.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java index b16bdf8cb5b..7039a4efa77 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java @@ -294,6 +294,7 @@ public class Huffman static final char[] rowsym; static final byte[] rowbits; + // Build the Huffman lookup tree static { int r=0; @@ -342,19 +343,21 @@ public class Huffman } - static public String decode(ByteBuffer buf) throws IOException - { - // TODO offer a version that does a direct lookup of compressed strings to known values - - StringBuilder out = new StringBuilder(buf.remaining()*2); + static public String decode(ByteBuffer buffer) throws IOException + { + StringBuilder out = new StringBuilder(buffer.remaining()*2); int node = 0; int current = 0; int bits = 0; - // TODO use buf array - while (buf.hasRemaining()) + byte[] array = buffer.array(); + int start=buffer.arrayOffset()+buffer.position(); + int end=start+buffer.remaining(); + buffer.position(buffer.limit()); + + for (int i=start; i= 8) @@ -395,11 +398,14 @@ public class Huffman } - static public void encode(ByteBuffer buf,String s) throws IOException + static public void encode(ByteBuffer buffer,String s) throws IOException { long current = 0; int n = 0; + byte[] array = buffer.array(); + int p=buffer.arrayOffset()+buffer.position(); + int len = s.length(); for (int i=0;i= 8) { n -= 8; - buf.put((byte)(current >> n)); + array[p++]=(byte)(current >> n); } } @@ -424,7 +430,9 @@ public class Huffman { current <<= (8 - n); current |= (0xFF >>> n); - buf.put((byte)current); + array[p++]=(byte)current; } + + buffer.position(p-buffer.arrayOffset()); } } From 953655af3171ea90f89277b940c3146a35517dc0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 2 Jun 2014 16:57:39 +0200 Subject: [PATCH 006/269] simplified nbit integers --- .../org/eclipse/jetty/hpack/NBitInteger.java | 144 ++++++------------ .../eclipse/jetty/hpack/NBitIntegerTest.java | 12 +- 2 files changed, 51 insertions(+), 105 deletions(-) diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java index 692a64542c1..e3568a0240d 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java @@ -22,103 +22,71 @@ import java.nio.ByteBuffer; public class NBitInteger { - public static void encode3(ByteBuffer buf, int n, int i) - { - int p=buf.position()-1; - - int nbits = 0xFF >>> (8 - 3); - if (i < nbits) + public static void encode(ByteBuffer buf, int n, int i) + { + if (n==8) { - buf.put(p,(byte)((buf.get(p)&~nbits)|i)); - } - else - { - buf.put(p,(byte)(buf.get(p)|nbits)); - - int length = i - nbits; - while (true) + if (i < 0xFF) { - if ((length & ~0x7F) == 0) + buf.put((byte)i); + } + else + { + buf.put((byte)0xFF); + + int length = i - 0xFF; + while (true) { - buf.put((byte)length); - return; - } - else - { - buf.put((byte)((length & 0x7F) | 0x80)); - length >>>= 7; + if ((length & ~0x7F) == 0) + { + buf.put((byte)length); + return; + } + else + { + buf.put((byte)((length & 0x7F) | 0x80)); + length >>>= 7; + } } } } - } - - - public static void encode5(ByteBuffer buf, int i) - { - int p=buf.position()-1; - int nbits = 0xFF >>> (8 - 5); - - if (i < nbits) - { - buf.put(p,(byte)((buf.get(p)&~nbits)|i)); - } else { - buf.put(p,(byte)(buf.get(p)|nbits)); - - int length = i - nbits; - while (true) + int p=buf.position()-1; + int bits = 0xFF >>> (8 - n); + + if (i < bits) { - if ((length & ~0x7F) == 0) - { - buf.put((byte)length); - return; - } - else - { - buf.put((byte)((length & 0x7F) | 0x80)); - length >>>= 7; - } + buf.put(p,(byte)((buf.get(p)&~bits)|i)); } - } - } - - - public static void encode8(ByteBuffer buf, int i) - { - int nbits = 0xFF; - - if (i < nbits) - { - buf.put((byte)i); - } - else - { - buf.put((byte)nbits); - - int length = i - nbits; - while (true) + else { - if ((length & ~0x7F) == 0) + buf.put(p,(byte)(buf.get(p)|bits)); + + int length = i - bits; + while (true) { - buf.put((byte)length); - return; - } - else - { - buf.put((byte)((length & 0x7F) | 0x80)); - length >>>= 7; + if ((length & ~0x7F) == 0) + { + buf.put((byte)length); + return; + } + else + { + buf.put((byte)((length & 0x7F) | 0x80)); + length >>>= 7; + } } } } } - public static int decode5(ByteBuffer buf) + public static int decode(ByteBuffer buf, int n) { - int nbits = 0xFF >>> (8 - 5); + int nbits = 0xFF >>> (8 - n); - int i=buf.get(buf.position()-1)&nbits; + int i=buf.get(buf.position()-n==8?0:1)&nbits; if (i == nbits) { @@ -134,26 +102,4 @@ public class NBitInteger } return i; } - - public static int decode8(ByteBuffer buf) - { - int nbits = 0xFF >>> (8 - 8); - - int i=buf.get()&nbits; - - if (i == nbits) - { - int m=1; - int b; - do - { - b = 0xff&buf.get(); - i = i + (b&127) * m; - m = m*128; - } - while ((b&128) == 128); - } - return i; - } - } diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java index 36900e31659..5e157577e8e 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java @@ -35,7 +35,7 @@ public class NBitIntegerTest int p=BufferUtil.flipToFill(buf); buf.put((byte)0x77); buf.put((byte)0xFF); - NBitInteger.encode5(buf,10); + NBitInteger.encode(buf,5,10); BufferUtil.flipToFlush(buf,p); String r=TypeUtil.toHexString(BufferUtil.toArray(buf)); @@ -50,7 +50,7 @@ public class NBitIntegerTest ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF")); buf.position(2); - Assert.assertEquals(10,NBitInteger.decode5(buf)); + Assert.assertEquals(10,NBitInteger.decode(buf,5)); } @@ -61,7 +61,7 @@ public class NBitIntegerTest int p=BufferUtil.flipToFill(buf); buf.put((byte)0x88); buf.put((byte)0x00); - NBitInteger.encode5(buf,1337); + NBitInteger.encode(buf,5,1337); BufferUtil.flipToFlush(buf,p); String r=TypeUtil.toHexString(BufferUtil.toArray(buf)); @@ -76,7 +76,7 @@ public class NBitIntegerTest ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff")); buf.position(2); - Assert.assertEquals(1337,NBitInteger.decode5(buf)); + Assert.assertEquals(1337,NBitInteger.decode(buf,5)); } @@ -87,7 +87,7 @@ public class NBitIntegerTest int p=BufferUtil.flipToFill(buf); buf.put((byte)0x88); buf.put((byte)0xFF); - NBitInteger.encode8(buf,42); + NBitInteger.encode(buf,8,42); BufferUtil.flipToFlush(buf,p); String r=TypeUtil.toHexString(BufferUtil.toArray(buf)); @@ -103,7 +103,7 @@ public class NBitIntegerTest ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf")); buf.position(1); - Assert.assertEquals(42,NBitInteger.decode8(buf)); + Assert.assertEquals(42,NBitInteger.decode(buf,8)); } From d19eef34035b3afcdf45ccd49bd191d3146f600b Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 4 Jun 2014 12:05:31 +0200 Subject: [PATCH 007/269] more tests --- jetty-hpack/pom.xml | 5 ++ .../java/org/eclipse/jetty/hpack/Huffman.java | 18 +++- .../org/eclipse/jetty/hpack/NBitInteger.java | 16 +++- .../org/eclipse/jetty/hpack/HuffmanTest.java | 1 + .../eclipse/jetty/hpack/NBitIntegerTest.java | 82 ++++++++++++++++++- .../org/eclipse/jetty/http/HttpField.java | 35 ++++++++ 6 files changed, 152 insertions(+), 5 deletions(-) diff --git a/jetty-hpack/pom.xml b/jetty-hpack/pom.xml index ecb70b102a9..8ff117c22a7 100644 --- a/jetty-hpack/pom.xml +++ b/jetty-hpack/pom.xml @@ -18,6 +18,11 @@ jetty-util ${project.version} + + org.eclipse.jetty + jetty-http + ${project.version} + org.eclipse.jetty.toolchain jetty-test-helper diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java index 7039a4efa77..a3f50dab39c 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java @@ -396,9 +396,23 @@ public class Huffman return out.toString(); } - - static public void encode(ByteBuffer buffer,String s) throws IOException + static public int octetsNeeded(String s) + { + int needed=0; + int len = s.length(); + for (int i=0;i=128) + throw new IllegalArgumentException(); + needed += CODES[c][1]; + } + + return (needed+7) / 8; + } + + static public void encode(ByteBuffer buffer,String s) { long current = 0; int n = 0; diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java index e3568a0240d..6be6e9b3bd1 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java @@ -22,7 +22,19 @@ import java.nio.ByteBuffer; public class NBitInteger { - + public static int octectsNeeded(int n,int i) + { + int nbits = 0xFF >>> (8 - n); + i=i-nbits; + if (i<0) + return n==8?1:0; + if (i==0) + return n==8?2:1; + int lz=Integer.numberOfLeadingZeros(i); + int log=32-lz; + return (log+6)/7; + } + public static void encode(ByteBuffer buf, int n, int i) { if (n==8) @@ -86,7 +98,7 @@ public class NBitInteger { int nbits = 0xFF >>> (8 - n); - int i=buf.get(buf.position()-n==8?0:1)&nbits; + int i=buf.get(buf.position()-(n==8?0:1))&nbits; if (i == nbits) { diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java index a68b16f2ebf..15066c5de86 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java @@ -38,6 +38,7 @@ public class HuffmanTest {"D.6.2te","abdd97ff","gzip"}, {"D.4.2cookie","e0d6cf9f6e8f9fd3e5f6fa76fefd3c7edf9eff1f2f0f3cfe9f6fcf7f8f879f61ad4f4cc9a973a2200ec3725e18b1b74e3f","foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"}, {"D.6.2date","d6dbb29884de2a718805062098513111b56ba3","Mon, 21 Oct 2013 20:13:22 GMT"}, + {"404","abdd97ff","404"}, }; @Test diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java index 5e157577e8e..9d0d1014c4f 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.hpack; +import static org.junit.Assert.assertEquals; + import java.nio.ByteBuffer; import org.eclipse.jetty.util.BufferUtil; @@ -28,6 +30,84 @@ import org.junit.Test; public class NBitIntegerTest { + @Test + public void testOctetsNeeded() + { + assertEquals(0,NBitInteger.octectsNeeded(5,10)); + assertEquals(2,NBitInteger.octectsNeeded(5,1337)); + assertEquals(1,NBitInteger.octectsNeeded(8,42)); + + assertEquals(0,NBitInteger.octectsNeeded(6,62)); + assertEquals(1,NBitInteger.octectsNeeded(6,63)); + assertEquals(1,NBitInteger.octectsNeeded(6,64)); + assertEquals(2,NBitInteger.octectsNeeded(6,63+0x00+0x80*0x01)); + assertEquals(3,NBitInteger.octectsNeeded(6,63+0x00+0x80*0x80)); + assertEquals(4,NBitInteger.octectsNeeded(6,63+0x00+0x80*0x80*0x80)); + } + + @Test + public void testEncode() + { + testEncode(6,0,"00"); + testEncode(6,1,"01"); + testEncode(6,62,"3e"); + testEncode(6,63,"3f00"); + testEncode(6,63+1,"3f01"); + testEncode(6,63+0x7e,"3f7e"); + testEncode(6,63+0x7f,"3f7f"); + testEncode(6,63+0x00+0x80*0x01,"3f8001"); + testEncode(6,63+0x01+0x80*0x01,"3f8101"); + testEncode(6,63+0x7f+0x80*0x01,"3fFf01"); + testEncode(6,63+0x00+0x80*0x02,"3f8002"); + testEncode(6,63+0x01+0x80*0x02,"3f8102"); + testEncode(6,63+0x7f+0x80*0x7f,"3fFf7f"); + testEncode(6,63+0x00+0x80*0x80, "3f808001"); + testEncode(6,63+0x7f+0x80*0x80*0x7f,"3fFf807f"); + testEncode(6,63+0x00+0x80*0x80*0x80,"3f80808001"); + } + + public void testEncode(int n,int i,String expected) + { + ByteBuffer buf = BufferUtil.allocate(16); + int p=BufferUtil.flipToFill(buf); + buf.put((byte)0x00); + NBitInteger.encode(buf,n,i); + BufferUtil.flipToFlush(buf,p); + String r=TypeUtil.toHexString(BufferUtil.toArray(buf)); + assertEquals(expected,r); + + assertEquals(expected.length()/2,1+NBitInteger.octectsNeeded(n,i)); + } + + @Test + public void testDecode() + { + testDecode(6,0,"00"); + testDecode(6,1,"01"); + testDecode(6,62,"3e"); + testDecode(6,63,"3f00"); + testDecode(6,63+1,"3f01"); + testDecode(6,63+0x7e,"3f7e"); + testDecode(6,63+0x7f,"3f7f"); + testDecode(6,63+0x80,"3f8001"); + testDecode(6,63+0x81,"3f8101"); + testDecode(6,63+0x7f+0x80*0x01,"3fFf01"); + testDecode(6,63+0x00+0x80*0x02,"3f8002"); + testDecode(6,63+0x01+0x80*0x02,"3f8102"); + testDecode(6,63+0x7f+0x80*0x7f,"3fFf7f"); + testDecode(6,63+0x00+0x80*0x80, "3f808001"); + testDecode(6,63+0x7f+0x80*0x80*0x7f,"3fFf807f"); + testDecode(6,63+0x00+0x80*0x80*0x80,"3f80808001"); + } + + + public void testDecode(int n,int expected,String encoded) + { + ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + buf.position(n==8?0:1); + Assert.assertEquals(expected,NBitInteger.decode(buf,n)); + } + @Test public void testEncodeExampleD_1_1() { @@ -40,7 +120,7 @@ public class NBitIntegerTest String r=TypeUtil.toHexString(BufferUtil.toArray(buf)); - Assert.assertEquals("77Ea",r); + assertEquals("77Ea",r); } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index 50f29b1ec18..aa7a63a8f1f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -85,5 +85,40 @@ public class HttpField return false; } + @Override + public boolean equals(Object o) + { + if (o==this) + return true; + if (!(o instanceof HttpField)) + return false; + HttpField field=(HttpField)o; + if (_header!=field.getHeader()) + return false; + if (!_name.equalsIgnoreCase(field.getName())) + return false; + if (_value==null && field.getValue()!=null) + return false; + if (!_value.equals(field.getValue())) + return false; + return true; + } + @Override + public int hashCode() + { + if (_header==null) + { + int hash=13; + int len = _name.length(); + for (int i = 0; i < len; i++) + { + char c = Character.toUpperCase(_name.charAt(i)); + hash = 31 * hash + c; + } + return _value.hashCode() ^ hash; + } + + return _value.hashCode() ^ _header.hashCode(); + } } From 637004d313e6706cf99649937746c6dc2e5ac6d8 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 4 Jun 2014 12:14:36 +0200 Subject: [PATCH 008/269] removed bad test --- .../src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java index 15066c5de86..a68b16f2ebf 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java @@ -38,7 +38,6 @@ public class HuffmanTest {"D.6.2te","abdd97ff","gzip"}, {"D.4.2cookie","e0d6cf9f6e8f9fd3e5f6fa76fefd3c7edf9eff1f2f0f3cfe9f6fcf7f8f879f61ad4f4cc9a973a2200ec3725e18b1b74e3f","foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"}, {"D.6.2date","d6dbb29884de2a718805062098513111b56ba3","Mon, 21 Oct 2013 20:13:22 GMT"}, - {"404","abdd97ff","404"}, }; @Test From b153430cee97d1c3675e144958ad73ccbfc45756 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 4 Jun 2014 13:18:22 +0200 Subject: [PATCH 009/269] added prototype encoder decoder APIs --- jetty-hpack/pom.xml | 5 + .../java/org/eclipse/jetty/hpack/Field.java | 74 +++++++++++++++ .../org/eclipse/jetty/hpack/HeaderTable.java | 91 +++++++++++++++++++ .../org/eclipse/jetty/hpack/HpackDecoder.java | 49 ++++++++++ .../org/eclipse/jetty/hpack/HpackEncoder.java | 44 +++++++++ 5 files changed, 263 insertions(+) create mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java create mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HeaderTable.java create mode 100644 jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoder.java create mode 100644 jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoder.java diff --git a/jetty-hpack/pom.xml b/jetty-hpack/pom.xml index 8ff117c22a7..ac68f3b1edd 100644 --- a/jetty-hpack/pom.xml +++ b/jetty-hpack/pom.xml @@ -23,6 +23,11 @@ jetty-http ${project.version} + + org.eclipse.jetty + jetty-io + ${project.version} + org.eclipse.jetty.toolchain jetty-test-helper diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java new file mode 100644 index 00000000000..6c0cd5b1803 --- /dev/null +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java @@ -0,0 +1,74 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpHeader; + +/* ------------------------------------------------------------ */ +/** + */ +public class Field extends HttpField +{ + // final ByteBuffer _nameLiteral; + // final ByteBuffer _nameHuffman; + + public Field(String name,String value) + { + super(HttpHeader.CACHE.get(name),name,value); + + // Generate a non huffman literal field + /* + _nameLiteral=BufferUtil.allocate(1+NBitInteger.octectsNeeded(7,name.length())+name.length()); + BufferUtil.flipToFill(_nameLiteral); + _nameLiteral.put((byte)0x00); + NBitInteger.encode(_nameLiteral,7,name.length()); + for (int i=0;i126) + throw new IllegalArgumentException(); + _nameLiteral.array()[_nameLiteral.position()+i]=(byte)c; + } + _nameLiteral.position(_nameLiteral.limit()); + BufferUtil.flipToFlush(_nameLiteral,0); + + // Generate a huffman literal field + int h=Huffman.octetsNeeded(name); + _nameHuffman=BufferUtil.allocate(1+NBitInteger.octectsNeeded(7,h)+h); + BufferUtil.flipToFill(_nameHuffman); + _nameHuffman.put((byte)0x80); + NBitInteger.encode(_nameHuffman,7,name.length()); + for (int i=0;i126) + throw new IllegalArgumentException(); + _nameHuffman.array()[_nameHuffman.position()+i]=(byte)c; + } + _nameHuffman.position(_nameHuffman.limit()); + BufferUtil.flipToFlush(_nameHuffman,0); + */ + + } +} + + + diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HeaderTable.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HeaderTable.java new file mode 100644 index 00000000000..e7c368d1932 --- /dev/null +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HeaderTable.java @@ -0,0 +1,91 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.hpack; + +public class HeaderTable +{ + + private static final String[][] STATIC_TABLE = + { + {null,null}, + /* 1 */ {":authority" ,""}, + /* 2 */ {":method" ,"GET"}, + /* 3 */ {":method" ,"POST"}, + /* 4 */ {":path" ,"/"}, + /* 5 */ {":path" ,"/index.html"}, + /* 6 */ {":scheme" ,"http"}, + /* 7 */ {":scheme" ,"https"}, + /* 8 */ {":status" ,"200"}, + /* 9 */ {":status" ,"204"}, + /* 10 */ {":status" ,"206"}, + /* 11 */ {":status" ,"304"}, + /* 12 */ {":status" ,"400"}, + /* 13 */ {":status" ,"404"}, + /* 14 */ {":status" ,"500"}, + /* 15 */ {"accept-charset" ,""}, + /* 16 */ {"accept-encoding" ,""}, + /* 17 */ {"accept-language" ,""}, + /* 18 */ {"accept-ranges" ,""}, + /* 19 */ {"accept" ,""}, + /* 20 */ {"access-control-allow-origin" ,""}, + /* 21 */ {"age" ,""}, + /* 22 */ {"allow" ,""}, + /* 23 */ {"authorization" ,""}, + /* 24 */ {"cache-control" ,""}, + /* 25 */ {"content-disposition" ,""}, + /* 26 */ {"content-encoding" ,""}, + /* 27 */ {"content-language" ,""}, + /* 28 */ {"content-length" ,""}, + /* 29 */ {"content-location" ,""}, + /* 30 */ {"content-range" ,""}, + /* 31 */ {"content-type" ,""}, + /* 32 */ {"cookie" ,""}, + /* 33 */ {"date" ,""}, + /* 34 */ {"etag" ,""}, + /* 35 */ {"expect" ,""}, + /* 36 */ {"expires" ,""}, + /* 37 */ {"from" ,""}, + /* 38 */ {"host" ,""}, + /* 39 */ {"if-match" ,""}, + /* 40 */ {"if-modified-since" ,""}, + /* 41 */ {"if-none-match" ,""}, + /* 42 */ {"if-range" ,""}, + /* 43 */ {"if-unmodified-since" ,""}, + /* 44 */ {"last-modified" ,""}, + /* 45 */ {"link" ,""}, + /* 46 */ {"location" ,""}, + /* 47 */ {"max-forwards" ,""}, + /* 48 */ {"proxy-authenticate" ,""}, + /* 49 */ {"proxy-authorization" ,""}, + /* 50 */ {"range" ,""}, + /* 51 */ {"referer" ,""}, + /* 52 */ {"refresh" ,""}, + /* 53 */ {"retry-after" ,""}, + /* 54 */ {"server" ,""}, + /* 55 */ {"set-cookie" ,""}, + /* 56 */ {"strict-transport-security" ,""}, + /* 57 */ {"transfer-encoding" ,""}, + /* 58 */ {"user-agent" ,""}, + /* 59 */ {"vary" ,""}, + /* 60 */ {"via" ,""}, + /* 61 */ {"www-authenticate" ,""}, + + }; + +} diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoder.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoder.java new file mode 100644 index 00000000000..cd2fe308303 --- /dev/null +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoder.java @@ -0,0 +1,49 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpField; + + +/* ------------------------------------------------------------ */ +/** + * This is not thread safe. May only be called by 1 thread at a time + */ +public class HpackDecoder +{ + public interface Listener + { + void emit(HttpField field); + void endHeaders(); + } + + public HpackDecoder(Listener listenr) + { + + } + + public void parse(ByteBuffer buffer) + { + + } + +} diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoder.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoder.java new file mode 100644 index 00000000000..e8a75171388 --- /dev/null +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoder.java @@ -0,0 +1,44 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.io.ByteBufferPool; + + +/* ------------------------------------------------------------ */ +/** + */ +public class HpackEncoder +{ + public HpackEncoder(ByteBufferPool pool) + { + + } + + public List encode(HttpFields fields) + { + return Collections.emptyList(); + } +} From 8f4aeeeb8dc4c6e8d4f1d831965df7fa8b4847b1 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 4 Jun 2014 15:08:54 +0200 Subject: [PATCH 010/269] updated version to 10.0.0-SNAPSHOT --- VERSION.txt | 2 ++ aggregates/jetty-all/pom.xml | 2 +- apache-jsp/pom.xml | 2 +- apache-jstl/pom.xml | 2 +- examples/async-rest/async-rest-jar/pom.xml | 2 +- examples/async-rest/async-rest-webapp/pom.xml | 2 +- examples/async-rest/pom.xml | 2 +- examples/embedded/pom.xml | 2 +- examples/pom.xml | 2 +- jetty-alpn/jetty-alpn-client/pom.xml | 2 +- jetty-alpn/jetty-alpn-server/pom.xml | 2 +- jetty-alpn/pom.xml | 2 +- jetty-annotations/pom.xml | 2 +- jetty-ant/pom.xml | 2 +- jetty-client/pom.xml | 2 +- jetty-continuation/pom.xml | 2 +- jetty-deploy/pom.xml | 2 +- jetty-distribution/pom.xml | 2 +- jetty-fcgi/fcgi-client/pom.xml | 2 +- jetty-fcgi/fcgi-server/pom.xml | 2 +- jetty-fcgi/pom.xml | 2 +- jetty-hpack/pom.xml | 2 +- jetty-http-spi/pom.xml | 2 +- jetty-http/pom.xml | 2 +- jetty-http2/pom.xml | 2 +- jetty-io/pom.xml | 2 +- jetty-jaas/pom.xml | 2 +- jetty-jaspi/pom.xml | 2 +- jetty-jmx/pom.xml | 2 +- jetty-jndi/pom.xml | 2 +- jetty-jsp/pom.xml | 2 +- jetty-jspc-maven-plugin/pom.xml | 2 +- jetty-maven-plugin/pom.xml | 2 +- jetty-monitor/pom.xml | 2 +- jetty-nosql/pom.xml | 2 +- jetty-osgi/jetty-osgi-alpn/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot-jsp/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot-warurl/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot/pom.xml | 2 +- jetty-osgi/jetty-osgi-httpservice/pom.xml | 2 +- jetty-osgi/jetty-osgi-npn/pom.xml | 2 +- jetty-osgi/pom.xml | 2 +- jetty-osgi/test-jetty-osgi-context/pom.xml | 2 +- jetty-osgi/test-jetty-osgi-webapp/pom.xml | 2 +- jetty-osgi/test-jetty-osgi/pom.xml | 2 +- jetty-plus/pom.xml | 2 +- jetty-proxy/pom.xml | 2 +- jetty-quickstart/pom.xml | 2 +- jetty-rewrite/pom.xml | 2 +- jetty-runner/pom.xml | 2 +- jetty-security/pom.xml | 2 +- jetty-server/pom.xml | 2 +- jetty-servlet/pom.xml | 2 +- jetty-servlets/pom.xml | 2 +- jetty-spdy/pom.xml | 2 +- jetty-spdy/spdy-alpn-tests/pom.xml | 2 +- jetty-spdy/spdy-client/pom.xml | 2 +- jetty-spdy/spdy-core/pom.xml | 2 +- jetty-spdy/spdy-example-webapp/pom.xml | 2 +- jetty-spdy/spdy-http-client-transport/pom.xml | 2 +- jetty-spdy/spdy-http-common/pom.xml | 2 +- jetty-spdy/spdy-http-server/pom.xml | 2 +- jetty-spdy/spdy-npn-tests/pom.xml | 2 +- jetty-spdy/spdy-server/pom.xml | 2 +- jetty-spring/pom.xml | 2 +- jetty-start/pom.xml | 2 +- jetty-util-ajax/pom.xml | 2 +- jetty-util/pom.xml | 2 +- jetty-webapp/pom.xml | 2 +- jetty-websocket/javax-websocket-client-impl/pom.xml | 2 +- jetty-websocket/javax-websocket-server-impl/pom.xml | 2 +- jetty-websocket/pom.xml | 2 +- jetty-websocket/websocket-api/pom.xml | 2 +- jetty-websocket/websocket-client/pom.xml | 2 +- jetty-websocket/websocket-common/pom.xml | 2 +- jetty-websocket/websocket-server/pom.xml | 2 +- jetty-websocket/websocket-servlet/pom.xml | 2 +- jetty-xml/pom.xml | 2 +- pom.xml | 4 +++- tests/pom.xml | 2 +- tests/test-continuation/pom.xml | 2 +- tests/test-integration/pom.xml | 2 +- tests/test-loginservice/pom.xml | 2 +- tests/test-sessions/pom.xml | 2 +- tests/test-sessions/test-hash-sessions/pom.xml | 2 +- tests/test-sessions/test-jdbc-sessions/pom.xml | 2 +- tests/test-sessions/test-sessions-common/pom.xml | 2 +- tests/test-webapps/pom.xml | 2 +- tests/test-webapps/test-jaas-webapp/pom.xml | 2 +- tests/test-webapps/test-jetty-webapp/pom.xml | 2 +- tests/test-webapps/test-jndi-webapp/pom.xml | 2 +- tests/test-webapps/test-mock-resources/pom.xml | 2 +- tests/test-webapps/test-proxy-webapp/pom.xml | 2 +- tests/test-webapps/test-servlet-spec/pom.xml | 2 +- .../test-servlet-spec/test-container-initializer/pom.xml | 2 +- tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml | 2 +- .../test-webapps/test-servlet-spec/test-web-fragment/pom.xml | 2 +- tests/test-webapps/test-webapp-rfc2616/pom.xml | 2 +- 98 files changed, 101 insertions(+), 97 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 97d997f30ed..8aa5803c532 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,3 +1,5 @@ +jetty-10.0.0-SNAPSHOT + jetty-9.2.0-SNAPSHOT jetty-9.2.0.RC0 - 15 May 2014 diff --git a/aggregates/jetty-all/pom.xml b/aggregates/jetty-all/pom.xml index c64b2bc8fa7..cb8ffa0df8f 100644 --- a/aggregates/jetty-all/pom.xml +++ b/aggregates/jetty-all/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/apache-jsp/pom.xml b/apache-jsp/pom.xml index 27bafe50066..17e94713700 100644 --- a/apache-jsp/pom.xml +++ b/apache-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 apache-jsp diff --git a/apache-jstl/pom.xml b/apache-jstl/pom.xml index 38c81584d04..9782ee66cdc 100644 --- a/apache-jstl/pom.xml +++ b/apache-jstl/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 apache-jstl diff --git a/examples/async-rest/async-rest-jar/pom.xml b/examples/async-rest/async-rest-jar/pom.xml index 9af20787489..e10ed25ed3c 100644 --- a/examples/async-rest/async-rest-jar/pom.xml +++ b/examples/async-rest/async-rest-jar/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 org.eclipse.jetty.example-async-rest diff --git a/examples/async-rest/async-rest-webapp/pom.xml b/examples/async-rest/async-rest-webapp/pom.xml index 1779812ea51..3b0adf80937 100644 --- a/examples/async-rest/async-rest-webapp/pom.xml +++ b/examples/async-rest/async-rest-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 org.eclipse.jetty.example-async-rest diff --git a/examples/async-rest/pom.xml b/examples/async-rest/pom.xml index 84bd9a4c112..4921cea51a4 100644 --- a/examples/async-rest/pom.xml +++ b/examples/async-rest/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.examples examples-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/examples/embedded/pom.xml b/examples/embedded/pom.xml index 30019e01b86..8441c8f65a4 100644 --- a/examples/embedded/pom.xml +++ b/examples/embedded/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.examples examples-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/examples/pom.xml b/examples/pom.xml index 737b90f6145..c2afbed3bb5 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml org.eclipse.jetty.examples diff --git a/jetty-alpn/jetty-alpn-client/pom.xml b/jetty-alpn/jetty-alpn-client/pom.xml index 0c3bb4dafeb..bc8b9059e38 100644 --- a/jetty-alpn/jetty-alpn-client/pom.xml +++ b/jetty-alpn/jetty-alpn-client/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-alpn-client diff --git a/jetty-alpn/jetty-alpn-server/pom.xml b/jetty-alpn/jetty-alpn-server/pom.xml index 6634192901b..a5b0a1e7719 100644 --- a/jetty-alpn/jetty-alpn-server/pom.xml +++ b/jetty-alpn/jetty-alpn-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-alpn-server diff --git a/jetty-alpn/pom.xml b/jetty-alpn/pom.xml index 689b859f091..179b06624e7 100644 --- a/jetty-alpn/pom.xml +++ b/jetty-alpn/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-alpn-parent diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index f07812ffce3..4fe968973e1 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-annotations diff --git a/jetty-ant/pom.xml b/jetty-ant/pom.xml index 3f9ade04e3c..d4233cf64d5 100644 --- a/jetty-ant/pom.xml +++ b/jetty-ant/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-ant diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index ea2eb2d4c01..62303365833 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index a926837af23..5d1fab51c6e 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-continuation diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index 0325c569dee..bff6397e2f4 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-deploy diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index d81eb575abf..2bc14963c46 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT jetty-distribution Jetty :: Distribution Assemblies diff --git a/jetty-fcgi/fcgi-client/pom.xml b/jetty-fcgi/fcgi-client/pom.xml index fc7542e28a2..2f460ee7f35 100644 --- a/jetty-fcgi/fcgi-client/pom.xml +++ b/jetty-fcgi/fcgi-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-fcgi/fcgi-server/pom.xml b/jetty-fcgi/fcgi-server/pom.xml index 4b343cbccbf..5117cdd7ee8 100644 --- a/jetty-fcgi/fcgi-server/pom.xml +++ b/jetty-fcgi/fcgi-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-fcgi/pom.xml b/jetty-fcgi/pom.xml index ff2f37caad5..9df08800c4e 100644 --- a/jetty-fcgi/pom.xml +++ b/jetty-fcgi/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-hpack/pom.xml b/jetty-hpack/pom.xml index ac68f3b1edd..c69b6798115 100644 --- a/jetty-hpack/pom.xml +++ b/jetty-hpack/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-hpack diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml index a21e2e3c9b4..05938667a22 100644 --- a/jetty-http-spi/pom.xml +++ b/jetty-http-spi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-http-spi diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 67d85ac6695..8f007daf70d 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-http diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index 7dfa284b525..bbe6a2137d3 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-http2 diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index c5879725d83..d54dd4289a5 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -2,7 +2,7 @@ jetty-project org.eclipse.jetty - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-io diff --git a/jetty-jaas/pom.xml b/jetty-jaas/pom.xml index ddc80f98e19..ea72da470e1 100644 --- a/jetty-jaas/pom.xml +++ b/jetty-jaas/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-jaas diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index 9f8fc89f2f4..3def5f7276d 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-jaspi diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index 56a5cae6286..7f73d687589 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-jmx diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index c40a6006d68..91155fece36 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-jndi diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml index c9002c22b11..e38af5c4976 100644 --- a/jetty-jsp/pom.xml +++ b/jetty-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-jsp diff --git a/jetty-jspc-maven-plugin/pom.xml b/jetty-jspc-maven-plugin/pom.xml index 2f709b2cd5c..cdbdb7344c3 100644 --- a/jetty-jspc-maven-plugin/pom.xml +++ b/jetty-jspc-maven-plugin/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-jspc-maven-plugin diff --git a/jetty-maven-plugin/pom.xml b/jetty-maven-plugin/pom.xml index eefa280e905..f9ad5fc4d62 100644 --- a/jetty-maven-plugin/pom.xml +++ b/jetty-maven-plugin/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-maven-plugin diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index 2b5611a9a1d..d6e5fac5805 100644 --- a/jetty-monitor/pom.xml +++ b/jetty-monitor/pom.xml @@ -19,7 +19,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-monitor diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index 7c4b1c86801..a6ba6a6cec5 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-nosql diff --git a/jetty-osgi/jetty-osgi-alpn/pom.xml b/jetty-osgi/jetty-osgi-alpn/pom.xml index 3698b98bca5..001c3349ede 100644 --- a/jetty-osgi/jetty-osgi-alpn/pom.xml +++ b/jetty-osgi/jetty-osgi-alpn/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-osgi-alpn diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index 8dfd29da12e..9aac5e0d75a 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-osgi-boot-jsp diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index a785f581868..88049e37084 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index 5a074b92430..e34518fb9de 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-osgi-boot diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml index 91087d7bcca..660aeb6bae8 100644 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml +++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-httpservice diff --git a/jetty-osgi/jetty-osgi-npn/pom.xml b/jetty-osgi/jetty-osgi-npn/pom.xml index db524d9a3c1..3319e6f753d 100644 --- a/jetty-osgi/jetty-osgi-npn/pom.xml +++ b/jetty-osgi/jetty-osgi-npn/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-osgi-npn diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index 6dbd99dcff7..25153de45d7 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT org.eclipse.jetty.osgi jetty-osgi-project diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml index 941b13bfb3c..d7bde5105ab 100644 --- a/jetty-osgi/test-jetty-osgi-context/pom.xml +++ b/jetty-osgi/test-jetty-osgi-context/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 test-jetty-osgi-context diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml index 1a0f37b6655..ef98098982f 100644 --- a/jetty-osgi/test-jetty-osgi-webapp/pom.xml +++ b/jetty-osgi/test-jetty-osgi-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index cf6810a052a..03938478c9d 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index d5485a11e66..79852c47586 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-plus diff --git a/jetty-proxy/pom.xml b/jetty-proxy/pom.xml index b17d0a1b114..feaff50afc6 100644 --- a/jetty-proxy/pom.xml +++ b/jetty-proxy/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-proxy diff --git a/jetty-quickstart/pom.xml b/jetty-quickstart/pom.xml index ad7e2dc028f..69dde04d135 100644 --- a/jetty-quickstart/pom.xml +++ b/jetty-quickstart/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 org.eclipse.jetty diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index 6b611c30cb8..0908ac2ca19 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-rewrite diff --git a/jetty-runner/pom.xml b/jetty-runner/pom.xml index 950f3b59279..57409ec4ded 100644 --- a/jetty-runner/pom.xml +++ b/jetty-runner/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-runner diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index e4071d23a6c..4e946580c63 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-security diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index f860621db6a..e8d6810553c 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-server diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index b9542c9c03b..3428ef0ef4d 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-servlet diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index 8f3d5af8d59..9b87556856e 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-servlets diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index 716ea6c83a2..5c9aa6f5f3c 100644 --- a/jetty-spdy/pom.xml +++ b/jetty-spdy/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-alpn-tests/pom.xml b/jetty-spdy/spdy-alpn-tests/pom.xml index d764d4a7404..3cb7f0103d5 100644 --- a/jetty-spdy/spdy-alpn-tests/pom.xml +++ b/jetty-spdy/spdy-alpn-tests/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml index 5bbfd331941..e70e92ca5fd 100644 --- a/jetty-spdy/spdy-client/pom.xml +++ b/jetty-spdy/spdy-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml index 8154ab7dbdc..4454b275d2f 100644 --- a/jetty-spdy/spdy-core/pom.xml +++ b/jetty-spdy/spdy-core/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml index 6cfb0d822ad..1ad01785443 100644 --- a/jetty-spdy/spdy-example-webapp/pom.xml +++ b/jetty-spdy/spdy-example-webapp/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 spdy-example-webapp diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml index 2d1d1d0143c..19fbdd07a5c 100644 --- a/jetty-spdy/spdy-http-client-transport/pom.xml +++ b/jetty-spdy/spdy-http-client-transport/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-http-common/pom.xml b/jetty-spdy/spdy-http-common/pom.xml index 61fa901d1fc..d98cbac88e2 100644 --- a/jetty-spdy/spdy-http-common/pom.xml +++ b/jetty-spdy/spdy-http-common/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml index dea1bf5726c..31565522f89 100644 --- a/jetty-spdy/spdy-http-server/pom.xml +++ b/jetty-spdy/spdy-http-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 spdy-http-server diff --git a/jetty-spdy/spdy-npn-tests/pom.xml b/jetty-spdy/spdy-npn-tests/pom.xml index 23464c50c21..5634fec5df7 100644 --- a/jetty-spdy/spdy-npn-tests/pom.xml +++ b/jetty-spdy/spdy-npn-tests/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index a67c83851e9..4e50110c334 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-spring/pom.xml b/jetty-spring/pom.xml index f4673999754..93af634e053 100644 --- a/jetty-spring/pom.xml +++ b/jetty-spring/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-spring diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 97040361bfd..6da601b807c 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-start diff --git a/jetty-util-ajax/pom.xml b/jetty-util-ajax/pom.xml index 26c34220b83..7cfc7d725fc 100644 --- a/jetty-util-ajax/pom.xml +++ b/jetty-util-ajax/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-util-ajax diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index 8850d89c2be..f958692563e 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-util diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index 6a62b70b1da..50f383d9815 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-webapp diff --git a/jetty-websocket/javax-websocket-client-impl/pom.xml b/jetty-websocket/javax-websocket-client-impl/pom.xml index 847dc893d50..b322d3fe8fe 100644 --- a/jetty-websocket/javax-websocket-client-impl/pom.xml +++ b/jetty-websocket/javax-websocket-client-impl/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/javax-websocket-server-impl/pom.xml b/jetty-websocket/javax-websocket-server-impl/pom.xml index 32e39012fdc..71e3bfcdf74 100644 --- a/jetty-websocket/javax-websocket-server-impl/pom.xml +++ b/jetty-websocket/javax-websocket-server-impl/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 596020b51bc..4d65f40246a 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-api/pom.xml b/jetty-websocket/websocket-api/pom.xml index 716dddb3b74..628d7cdd8a4 100644 --- a/jetty-websocket/websocket-api/pom.xml +++ b/jetty-websocket/websocket-api/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-client/pom.xml b/jetty-websocket/websocket-client/pom.xml index 5e516d64b1e..a0b91e6f6f1 100644 --- a/jetty-websocket/websocket-client/pom.xml +++ b/jetty-websocket/websocket-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-common/pom.xml b/jetty-websocket/websocket-common/pom.xml index 7a7fa30660e..98bdd5a68ae 100644 --- a/jetty-websocket/websocket-common/pom.xml +++ b/jetty-websocket/websocket-common/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-server/pom.xml b/jetty-websocket/websocket-server/pom.xml index 19def583bfe..5f55cccf418 100644 --- a/jetty-websocket/websocket-server/pom.xml +++ b/jetty-websocket/websocket-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-servlet/pom.xml b/jetty-websocket/websocket-servlet/pom.xml index 1aa7f66a01f..34126478ea3 100644 --- a/jetty-websocket/websocket-servlet/pom.xml +++ b/jetty-websocket/websocket-servlet/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index 517cd7e972d..70a6487a960 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 jetty-xml diff --git a/pom.xml b/pom.xml index 87c22e7a987..b98727a699e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 22 jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT Jetty :: Project http://www.eclipse.org/jetty pom @@ -412,6 +412,8 @@ jetty-jmx jetty-io jetty-http + jetty-hpack + jetty-http2 jetty-continuation jetty-server jetty-xml diff --git a/tests/pom.xml b/tests/pom.xml index 717de70e7d0..e2398f4638d 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty jetty-project - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml org.eclipse.jetty.tests diff --git a/tests/test-continuation/pom.xml b/tests/test-continuation/pom.xml index fd6cc1e7913..2a0e01889e3 100644 --- a/tests/test-continuation/pom.xml +++ b/tests/test-continuation/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests tests-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml index 928ec922c1b..d6a5433bc5c 100644 --- a/tests/test-integration/pom.xml +++ b/tests/test-integration/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests tests-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT 4.0.0 test-integration diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml index 263585acac2..9d039866f16 100644 --- a/tests/test-loginservice/pom.xml +++ b/tests/test-loginservice/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-loginservice Jetty Tests :: Login Service diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml index ec7205b9866..697a0ff9b9f 100644 --- a/tests/test-sessions/pom.xml +++ b/tests/test-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-sessions-parent Jetty Tests :: Sessions :: Parent diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index 45b53ee1ce9..88511cfbfef 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-hash-sessions Jetty Tests :: Sessions :: Hash diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 8eebb4cdfda..0f501679a1e 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-jdbc-sessions Jetty Tests :: Sessions :: JDBC diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index c3830b8b2cb..3c9cf038d42 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-sessions-common Jetty Tests :: Sessions :: Common diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index 702fb1bdd64..72ffebae9c0 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml test-webapps-parent diff --git a/tests/test-webapps/test-jaas-webapp/pom.xml b/tests/test-webapps/test-jaas-webapp/pom.xml index e86e72eec56..e3d0047c21e 100644 --- a/tests/test-webapps/test-jaas-webapp/pom.xml +++ b/tests/test-webapps/test-jaas-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-jaas-webapp Jetty Tests :: WebApp :: JAAS diff --git a/tests/test-webapps/test-jetty-webapp/pom.xml b/tests/test-webapps/test-jetty-webapp/pom.xml index 732c304c20d..b952e3c4d3f 100644 --- a/tests/test-webapps/test-jetty-webapp/pom.xml +++ b/tests/test-webapps/test-jetty-webapp/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-webapps/test-jndi-webapp/pom.xml b/tests/test-webapps/test-jndi-webapp/pom.xml index ddfe948886d..04b130d2be6 100644 --- a/tests/test-webapps/test-jndi-webapp/pom.xml +++ b/tests/test-webapps/test-jndi-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-jndi-webapp Jetty Tests :: WebApp :: JNDI diff --git a/tests/test-webapps/test-mock-resources/pom.xml b/tests/test-webapps/test-mock-resources/pom.xml index c8e313d68f1..7704f0ccd3e 100644 --- a/tests/test-webapps/test-mock-resources/pom.xml +++ b/tests/test-webapps/test-mock-resources/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT Jetty Tests :: WebApp :: Mock Resources test-mock-resources diff --git a/tests/test-webapps/test-proxy-webapp/pom.xml b/tests/test-webapps/test-proxy-webapp/pom.xml index 61c13f98db0..629a792c9e5 100644 --- a/tests/test-webapps/test-proxy-webapp/pom.xml +++ b/tests/test-webapps/test-proxy-webapp/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-webapps/test-servlet-spec/pom.xml b/tests/test-webapps/test-servlet-spec/pom.xml index 07ec7eed81e..e1baa56d470 100644 --- a/tests/test-webapps/test-servlet-spec/pom.xml +++ b/tests/test-webapps/test-servlet-spec/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-servlet-spec-parent Jetty Tests :: Spec Test WebApp :: Parent diff --git a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml index 9210babeddc..e7939f8cb0f 100644 --- a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-container-initializer jar diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml index 440a58c4581..0246904e8db 100644 --- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT Jetty Tests :: Webapps :: Spec Webapp test-spec-webapp diff --git a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml index da0f311eb92..67c7d86508e 100644 --- a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT Jetty Tests :: WebApp :: Servlet Spec :: Fragment Jar org.eclipse.jetty.tests diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml index eeba7378f6f..40401a12f89 100644 --- a/tests/test-webapps/test-webapp-rfc2616/pom.xml +++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-webapps-parent - 9.2.0-SNAPSHOT + 10.0.0-SNAPSHOT test-webapp-rfc2616 Jetty Tests :: WebApp :: RFC2616 From 2b0f983b9c9e034948ee02c313c030add8125f78 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 4 Jun 2014 18:00:43 +0200 Subject: [PATCH 011/269] moved from test --- .../{test => main}/java/org/eclipse/jetty/hpack/HpackDecoder.java | 0 .../{test => main}/java/org/eclipse/jetty/hpack/HpackEncoder.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename jetty-hpack/src/{test => main}/java/org/eclipse/jetty/hpack/HpackDecoder.java (100%) rename jetty-hpack/src/{test => main}/java/org/eclipse/jetty/hpack/HpackEncoder.java (100%) diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java similarity index 100% rename from jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoder.java rename to jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java similarity index 100% rename from jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoder.java rename to jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java From a7e5963dfa5011cb04f40529d97b5ebd92b2b0c7 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 5 Jun 2014 18:11:22 +0200 Subject: [PATCH 012/269] Implemented parser and generator for DATA frame. --- jetty-http2/pom.xml | 5 + .../eclipse/jetty/http2/frames/DataFrame.java | 52 ++++++ .../jetty/http2/generator/Generator.java | 155 ++++++++++++++++ .../jetty/http2/parser/BodyParser.java | 36 ++++ .../jetty/http2/parser/DataBodyParser.java | 156 ++++++++++++++++ .../jetty/http2/parser/HeaderParser.java | 148 +++++++++++++++ .../eclipse/jetty/http2/parser/Parser.java | 96 ++++++++++ .../http2/frames/DataGenerateParseTest.java | 174 ++++++++++++++++++ 8 files changed, 822 insertions(+) create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java create mode 100644 jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index bbe6a2137d3..f1178b35ded 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -13,6 +13,11 @@ ${project.groupId}.http + + org.eclipse.jetty + jetty-io + ${project.version} + org.eclipse.jetty jetty-util diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java new file mode 100644 index 00000000000..84128a89ef1 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -0,0 +1,52 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; + +public class DataFrame +{ + public static final int MAX_LENGTH = 0x3F_FF; + + private final int streamId; + private final ByteBuffer data; + private boolean end; + + public DataFrame(int streamId, ByteBuffer data, boolean end) + { + this.streamId = streamId; + this.data = data; + this.end = end; + } + + public int getStreamId() + { + return streamId; + } + + public boolean isEnd() + { + return end; + } + + public ByteBuffer getData() + { + return data; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java new file mode 100644 index 00000000000..5d27b743677 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -0,0 +1,155 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; + +public class Generator +{ + private final ByteBufferPool byteBufferPool; + + public Generator(ByteBufferPool byteBufferPool) + { + this.byteBufferPool = byteBufferPool; + } + + public Result generateContent(int streamId, int paddingLength, ByteBuffer data, boolean last, boolean compress) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + // Leave space for at least one byte of content. + if (paddingLength > DataFrame.MAX_LENGTH - 3) + throw new IllegalArgumentException("Invalid padding length: " + paddingLength); + + int paddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; + + // TODO: here we should compress the data, and then reason on the data length ! + + int dataLength = data.remaining(); + + Result result = new Result(byteBufferPool); + + // Can we fit just one frame ? + if (dataLength + paddingBytes + paddingLength <= DataFrame.MAX_LENGTH) + { + generateFrame(result, streamId, paddingBytes, paddingLength, data, last, compress); + } + else + { + int dataBytesPerFrame = DataFrame.MAX_LENGTH - paddingBytes - paddingLength; + int frames = dataLength / dataBytesPerFrame; + if (frames * dataBytesPerFrame != dataLength) + { + ++frames; + } + int limit = data.limit(); + for (int i = 1; i <= frames; ++i) + { + data.limit(Math.min(dataBytesPerFrame * i, limit)); + ByteBuffer slice = data.slice(); + data.position(data.limit()); + generateFrame(result, streamId, paddingBytes, paddingLength, slice, i == frames && last, compress); + } + } + return result; + } + + private void generateFrame(Result result, int streamId, int paddingBytes, int paddingLength, ByteBuffer data, boolean last, boolean compress) + { + ByteBuffer header = byteBufferPool.acquire(8 + paddingBytes, true); + BufferUtil.clearToFill(header); + + int length = paddingBytes + data.remaining() + paddingLength; + header.putShort((short)length); + + // Frame type for DATA frames is 0. + header.put((byte)0); + + int flags = 0; + if (last) + flags |= 0x01; + if (paddingBytes > 0) + flags |= 0x08; + if (paddingBytes > 1) + flags |= 0x10; + if (compress) + flags |= 0x20; + header.put((byte)flags); + + header.putInt(streamId); + + if (paddingBytes == 2) + header.putShort((short)paddingLength); + else if (paddingBytes == 1) + header.put((byte)paddingLength); + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + + result.add(data, false); + + if (paddingBytes > 0) + { + ByteBuffer padding = byteBufferPool.acquire(paddingLength, true); + BufferUtil.clearToFill(padding); + padding.position(paddingLength); + BufferUtil.flipToFlush(padding, 0); + result.add(padding, true); + } + } + + public static class Result + { + private final ByteBufferPool byteBufferPool; + private final List buffers; + private final List recycles; + + public Result(ByteBufferPool byteBufferPool) + { + this.byteBufferPool = byteBufferPool; + this.buffers = new ArrayList<>(); + this.recycles = new ArrayList<>(); + } + + public void add(ByteBuffer buffer, boolean recycle) + { + buffers.add(buffer); + recycles.add(recycle); + } + + public List getByteBuffers() + { + return buffers; + } + + public Result merge(Result that) + { + assert byteBufferPool == that.byteBufferPool; + buffers.addAll(that.buffers); + recycles.addAll(that.recycles); + return this; + } + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java new file mode 100644 index 00000000000..fbcc9551a22 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -0,0 +1,36 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public abstract class BodyParser +{ + protected static final Logger LOG = Log.getLogger(BodyParser.class); + + public abstract Result parse(ByteBuffer buffer); + + public enum Result + { + PENDING, ASYNC, COMPLETE + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java new file mode 100644 index 00000000000..ab6671b4de1 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -0,0 +1,156 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.DataFrame; + +public class DataBodyParser extends BodyParser +{ + private final HeaderParser headerParser; + private final Parser.Listener listener; + private State state = State.PREPARE; + private int paddingLength; + private int length; + + public DataBodyParser(HeaderParser headerParser, Parser.Listener listener) + { + this.headerParser = headerParser; + this.listener = listener; + } + + private void reset() + { + headerParser.reset(); + state = State.PREPARE; + paddingLength = 0; + length = 0; + } + + @Override + public Result parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case PREPARE: + { + length = headerParser.getLength(); + if (headerParser.isPaddingHigh()) + { + state = State.PADDING_HIGH; + } + else if (headerParser.isPaddingLow()) + { + state = State.PADDING_LOW; + } + else + { + state = State.DATA; + } + break; + } + case PADDING_HIGH: + { + paddingLength = (buffer.get() & 0xFF) << 8; + length -= 1; + state = State.PADDING_LOW; + break; + } + case PADDING_LOW: + { + paddingLength += buffer.get() & 0xFF; + length -= 1; + length -= paddingLength; + state = State.DATA; + break; + } + case DATA: + { + int size = Math.min(buffer.remaining(), length); + int position = buffer.position(); + int limit = buffer.limit(); + buffer.limit(position + size); + ByteBuffer slice = buffer.slice(); + buffer.limit(limit); + buffer.position(position + size); + + length -= size; + if (length == 0) + { + state = State.PADDING; + if (onData(slice, false)) + { + return Result.ASYNC; + } + } + else + { + // We got partial data, fake the frame. + if (onData(slice, true)) + { + return Result.ASYNC; + } + } + break; + } + case PADDING: + { + int size = Math.min(buffer.remaining(), paddingLength); + buffer.position(buffer.position() + size); + paddingLength -= size; + if (paddingLength == 0) + { + reset(); + return Result.COMPLETE; + } + break; + } + } + } + return Result.PENDING; + } + + private boolean onData(ByteBuffer buffer, boolean fragment) + { + boolean end = headerParser.isEndStream(); + DataFrame frame = new DataFrame(headerParser.getStreamId(), buffer, fragment ? false : end); + return notifyDataFrame(frame); + } + + protected boolean notifyDataFrame(DataFrame frame) + { + try + { + return listener.onDataFrame(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + + private enum State + { + PREPARE, PADDING_HIGH, PADDING_LOW, DATA, PADDING + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java new file mode 100644 index 00000000000..27e1bb9ac74 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java @@ -0,0 +1,148 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.DataFrame; + +public class HeaderParser +{ + private State state = State.LENGTH; + private int cursor; + + private int length; + private int type; + private int flags; + private int streamId; + + protected void reset() + { + state = State.LENGTH; + cursor = 0; + + length = 0; + type = 0; + flags = 0; + streamId = 0; + } + + public boolean parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case LENGTH: + { + int halfShort = buffer.get() & 0xFF; + length = (length << 8) + halfShort; + if (++cursor == 2) + { + // First 2 most significant bits MUST be ignored as per specification. + length &= DataFrame.MAX_LENGTH; + state = State.TYPE; + } + break; + } + case TYPE: + { + type = buffer.get() & 0xFF; + state = State.FLAGS; + break; + } + case FLAGS: + { + flags = buffer.get() & 0xFF; + state = State.STREAM_ID; + break; + } + case STREAM_ID: + { + if (buffer.remaining() >= 4) + { + streamId = buffer.getInt(); + // Most significant bit MUST be ignored as per specification. + streamId &= 0x7F_FF_FF_FF; + return true; + } + else + { + state = State.STREAM_ID_BYTES; + cursor = 4; + } + break; + } + case STREAM_ID_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + streamId += currByte << (8 * cursor); + if (cursor == 0) + { + // Most significant bit MUST be ignored as per specification. + streamId &= 0x7F_FF_FF_FF; + return true; + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return false; + } + + public int getLength() + { + return length; + } + + public int getFrameType() + { + return type; + } + + public boolean isPaddingHigh() + { + return (flags & 0x10) == 0x10; + } + + public boolean isPaddingLow() + { + return (flags & 0x08) == 0x08; + } + + public boolean isEndStream() + { + return (flags & 0x01) == 0x01; + } + + public int getStreamId() + { + return streamId; + } + + private enum State + { + LENGTH, TYPE, FLAGS, STREAM_ID, STREAM_ID_BYTES + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java new file mode 100644 index 00000000000..82aa30e82e6 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -0,0 +1,96 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.DataFrame; + +public class Parser +{ + private final HeaderParser headerParser = new HeaderParser(); + private final BodyParser[] bodyParsers = new BodyParser[1]; + private State state = State.HEADER; + private BodyParser bodyParser; + + public Parser(Listener listener) + { + bodyParsers[0] = new DataBodyParser(headerParser, listener); + } + + private void reset() + { + state = State.HEADER; + } + + public boolean parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case HEADER: + { + if (headerParser.parse(buffer)) + { + int type = headerParser.getFrameType(); + bodyParser = bodyParsers[type]; + state = State.BODY; + } + break; + } + case BODY: + { + BodyParser.Result result = bodyParser.parse(buffer); + if (result == BodyParser.Result.ASYNC) + { + // The content will be processed asynchronously, stop parsing; + // the asynchronous operation will eventually resume parsing. + return true; + } + else if (result == BodyParser.Result.COMPLETE) + { + reset(); + } + break; + } + } + } + return false; + } + + public interface Listener + { + public boolean onDataFrame(DataFrame frame); + + public static class Adapter implements Listener + { + @Override + public boolean onDataFrame(DataFrame frame) + { + return false; + } + } + } + + private enum State + { + HEADER, BODY + } +} diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java new file mode 100644 index 00000000000..ab90ca26237 --- /dev/null +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -0,0 +1,174 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Test; + +public class DataGenerateParseTest +{ + private final byte[] smallContent = new byte[128]; + private final byte[] largeContent = new byte[128 * 1024]; + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + public DataGenerateParseTest() + { + Random random = new Random(); + random.nextBytes(smallContent); + random.nextBytes(largeContent); + } + + @Test + public void testGenerateParseSmallContentNoPadding() + { + testGenerateParseSmallContent(0); + } + + @Test + public void testGenerateParseSmallContentSmallPadding() + { + testGenerateParseSmallContent(128); + } + + @Test + public void testGenerateParseSmallContentLargePadding() + { + testGenerateParseSmallContent(1024); + } + + private void testGenerateParseSmallContent(int paddingLength) + { + ByteBuffer content = ByteBuffer.wrap(smallContent); + List frames = testGenerateParse(paddingLength, content); + Assert.assertEquals(1, frames.size()); + DataFrame frame = frames.get(0); + Assert.assertTrue(frame.getStreamId() != 0); + Assert.assertTrue(frame.isEnd()); + Assert.assertEquals(content, frame.getData()); + } + + @Test + public void testGenerateParseLargeContent() + { + testGenerateParseLargeContent(0); + } + + @Test + public void testGenerateParseLargeContentSmallPadding() + { + testGenerateParseLargeContent(128); + } + + @Test + public void testGenerateParseLargeContentLargePadding() + { + testGenerateParseLargeContent(1024); + } + + private void testGenerateParseLargeContent(int paddingLength) + { + ByteBuffer content = ByteBuffer.wrap(largeContent); + List frames = testGenerateParse(paddingLength, content); + Assert.assertEquals(9, frames.size()); + ByteBuffer aggregate = ByteBuffer.allocate(content.remaining()); + for (int i = 1; i <= frames.size(); ++i) + { + DataFrame frame = frames.get(i - 1); + Assert.assertTrue(frame.getStreamId() != 0); + Assert.assertEquals(i == frames.size(), frame.isEnd()); + aggregate.put(frame.getData()); + } + aggregate.flip(); + Assert.assertEquals(content, aggregate); + } + + private List testGenerateParse(int paddingLength, ByteBuffer... data) + { + Generator generator = new Generator(byteBufferPool); + + // Iterate a few times to be sure generator + // and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + Generator.Result result = new Generator.Result(byteBufferPool); + for (int j = 1; j <= data.length; ++j) + { + result = result.merge(generator.generateContent(13, paddingLength, data[j - 1].slice(), j == data.length, false)); + } + + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onDataFrame(DataFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : result.getByteBuffers()) + { + parser.parse(buffer); + } + } + + return frames; + } + + @Test + public void testGenerateParseOneByteAtATime() + { + Generator generator = new Generator(byteBufferPool); + + Generator.Result result = new Generator.Result(byteBufferPool); + result = result.merge(generator.generateContent(13, 1024, ByteBuffer.wrap(largeContent).slice(), true, false)); + + final List frames = new ArrayList<>(); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onDataFrame(DataFrame frame) + { + frames.add(frame); + return false; + } + }); + + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(largeContent.length, frames.size()); + } +} From 21d8435541e14aef298684e2b2e7b03ad2268684 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 5 Jun 2014 19:26:53 +0200 Subject: [PATCH 013/269] Implemented parser and generator for PRIORITY frame. --- .../eclipse/jetty/http2/frames/FrameType.java | 36 ++++++ .../jetty/http2/frames/PriorityFrame.java | 55 ++++++++ .../jetty/http2/generator/Generator.java | 36 +++++- .../jetty/http2/parser/BodyParser.java | 67 ++++++++++ .../jetty/http2/parser/DataBodyParser.java | 37 ++---- .../eclipse/jetty/http2/parser/Parser.java | 16 ++- .../http2/parser/PriorityBodyParser.java | 118 ++++++++++++++++++ .../http2/frames/DataGenerateParseTest.java | 6 +- .../frames/PriorityGenerateParseTest.java | 99 +++++++++++++++ 9 files changed, 439 insertions(+), 31 deletions(-) create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java create mode 100644 jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java new file mode 100644 index 00000000000..e9c80df8200 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java @@ -0,0 +1,36 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public enum FrameType +{ + DATA(0), HEADERS(1), PRIORITY(2); + + private final int type; + + private FrameType(int type) + { + this.type = type; + } + + public int getType() + { + return type; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java new file mode 100644 index 00000000000..e82a3c4be02 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java @@ -0,0 +1,55 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class PriorityFrame +{ + private final int streamId; + private final int dependentStreamId; + private final int weight; + private final boolean exclusive; + + public PriorityFrame(int streamId, int dependentStreamId, int weight, boolean exclusive) + { + this.streamId = streamId; + this.dependentStreamId = dependentStreamId; + this.weight = weight; + this.exclusive = exclusive; + } + + public int getStreamId() + { + return streamId; + } + + public int getDependentStreamId() + { + return dependentStreamId; + } + + public int getWeight() + { + return weight; + } + + public boolean isExclusive() + { + return exclusive; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 5d27b743677..2c5c6ff66ca 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; @@ -35,6 +36,38 @@ public class Generator this.byteBufferPool = byteBufferPool; } + public Result generatePriority(int streamId, int dependentStreamId, int weight, boolean exclusive) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + if (dependentStreamId < 0) + throw new IllegalArgumentException("Invalid dependent stream id: " + dependentStreamId); + + ByteBuffer header = byteBufferPool.acquire(8 + 5, true); + BufferUtil.clearToFill(header); + + Result result = new Result(byteBufferPool); + header.putShort((short)5); + + header.put((byte)FrameType.PRIORITY.getType()); + // No flags. + header.put((byte)0); + + header.putInt(dependentStreamId); + + if (exclusive) + streamId |= 0x80_00_00_00; + + header.putInt(streamId); + + header.put((byte)weight); + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + + return result; + } + public Result generateContent(int streamId, int paddingLength, ByteBuffer data, boolean last, boolean compress) { if (streamId < 0) @@ -84,8 +117,7 @@ public class Generator int length = paddingBytes + data.remaining() + paddingLength; header.putShort((short)length); - // Frame type for DATA frames is 0. - header.put((byte)0); + header.put((byte)FrameType.DATA.getType()); int flags = 0; if (last) diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index fbcc9551a22..85da726fef2 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -20,6 +20,8 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -27,8 +29,73 @@ public abstract class BodyParser { protected static final Logger LOG = Log.getLogger(BodyParser.class); + private final HeaderParser headerParser; + private final Parser.Listener listener; + + protected BodyParser(HeaderParser headerParser, Parser.Listener listener) + { + this.headerParser = headerParser; + this.listener = listener; + } + public abstract Result parse(ByteBuffer buffer); + protected boolean isPaddingHigh() + { + return headerParser.isPaddingHigh(); + } + + protected boolean isPaddingLow() + { + return headerParser.isPaddingLow(); + } + + protected boolean isEndStream() + { + return headerParser.isEndStream(); + } + + protected int getStreamId() + { + return headerParser.getStreamId(); + } + + protected int getBodyLength() + { + return headerParser.getLength(); + } + + protected void reset() + { + headerParser.reset(); + } + + protected boolean notifyDataFrame(DataFrame frame) + { + try + { + return listener.onDataFrame(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + + protected boolean notifyPriorityFrame(PriorityFrame frame) + { + try + { + return listener.onPriorityFrame(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + public enum Result { PENDING, ASYNC, COMPLETE diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index ab6671b4de1..5bd3d46cff7 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -24,21 +24,19 @@ import org.eclipse.jetty.http2.frames.DataFrame; public class DataBodyParser extends BodyParser { - private final HeaderParser headerParser; - private final Parser.Listener listener; private State state = State.PREPARE; private int paddingLength; private int length; public DataBodyParser(HeaderParser headerParser, Parser.Listener listener) { - this.headerParser = headerParser; - this.listener = listener; + super(headerParser, listener); } - private void reset() + @Override + protected void reset() { - headerParser.reset(); + super.reset(); state = State.PREPARE; paddingLength = 0; length = 0; @@ -53,12 +51,12 @@ public class DataBodyParser extends BodyParser { case PREPARE: { - length = headerParser.getLength(); - if (headerParser.isPaddingHigh()) + length = getBodyLength(); + if (isPaddingHigh()) { state = State.PADDING_HIGH; } - else if (headerParser.isPaddingLow()) + else if (isPaddingLow()) { state = State.PADDING_LOW; } @@ -124,6 +122,10 @@ public class DataBodyParser extends BodyParser } break; } + default: + { + throw new IllegalStateException(); + } } } return Result.PENDING; @@ -131,24 +133,11 @@ public class DataBodyParser extends BodyParser private boolean onData(ByteBuffer buffer, boolean fragment) { - boolean end = headerParser.isEndStream(); - DataFrame frame = new DataFrame(headerParser.getStreamId(), buffer, fragment ? false : end); + boolean end = isEndStream(); + DataFrame frame = new DataFrame(getStreamId(), buffer, fragment ? false : end); return notifyDataFrame(frame); } - protected boolean notifyDataFrame(DataFrame frame) - { - try - { - return listener.onDataFrame(frame); - } - catch (Throwable x) - { - LOG.info("Failure while notifying listener " + listener, x); - return false; - } - } - private enum State { PREPARE, PADDING_HIGH, PADDING_LOW, DATA, PADDING diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 82aa30e82e6..21b0dbdc3db 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -21,17 +21,19 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.PriorityFrame; public class Parser { private final HeaderParser headerParser = new HeaderParser(); - private final BodyParser[] bodyParsers = new BodyParser[1]; + private final BodyParser[] bodyParsers = new BodyParser[3]; private State state = State.HEADER; private BodyParser bodyParser; public Parser(Listener listener) { bodyParsers[0] = new DataBodyParser(headerParser, listener); + bodyParsers[2] = new PriorityBodyParser(headerParser, listener); } private void reset() @@ -70,6 +72,10 @@ public class Parser } break; } + default: + { + throw new IllegalStateException(); + } } } return false; @@ -79,6 +85,8 @@ public class Parser { public boolean onDataFrame(DataFrame frame); + public boolean onPriorityFrame(PriorityFrame frame); + public static class Adapter implements Listener { @Override @@ -86,6 +94,12 @@ public class Parser { return false; } + + @Override + public boolean onPriorityFrame(PriorityFrame frame) + { + return false; + } } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java new file mode 100644 index 00000000000..91968319a7b --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -0,0 +1,118 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.PriorityFrame; + +public class PriorityBodyParser extends BodyParser +{ + private State state = State.EXCLUSIVE; + private int cursor; + + private boolean exclusive; + private int streamId; + + public PriorityBodyParser(HeaderParser headerParser, Parser.Listener listener) + { + super(headerParser, listener); + } + + @Override + protected void reset() + { + super.reset(); + state = State.EXCLUSIVE; + cursor = 0; + + exclusive = false; + streamId = 0; + } + + @Override + public Result parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case EXCLUSIVE: + { + // We must only peek the first byte and not advance the buffer + // because the 31 least significant bits represent the stream id. + int currByte = buffer.get(buffer.position()); + exclusive = (currByte & 0x80) == 0x80; + state = State.STREAM_ID; + break; + } + case STREAM_ID: + { + if (buffer.remaining() >= 4) + { + streamId = buffer.getInt(); + streamId &= 0x7F_FF_FF_FF; + state = State.WEIGHT; + } + else + { + state = State.STREAM_ID_BYTES; + cursor = 4; + } + break; + } + case STREAM_ID_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + streamId += currByte << (8 * cursor); + if (cursor == 0) + { + streamId &= 0x7F_FF_FF_FF; + state = State.WEIGHT; + } + break; + } + case WEIGHT: + { + int weight = buffer.get() & 0xFF; + boolean async = onPriority(weight); + reset(); + return async ? Result.ASYNC : Result.COMPLETE; + } + default: + { + throw new IllegalStateException(); + } + } + } + return Result.PENDING; + } + + private boolean onPriority(int weight) + { + PriorityFrame frame = new PriorityFrame(streamId, getStreamId(), weight, exclusive); + return notifyPriorityFrame(frame); + } + + private enum State + { + EXCLUSIVE, STREAM_ID, STREAM_ID_BYTES, WEIGHT + } +} diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index ab90ca26237..d138fb5de8d 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -111,8 +111,7 @@ public class DataGenerateParseTest { Generator generator = new Generator(byteBufferPool); - // Iterate a few times to be sure generator - // and parser are properly reset. + // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { @@ -147,8 +146,7 @@ public class DataGenerateParseTest { Generator generator = new Generator(byteBufferPool); - Generator.Result result = new Generator.Result(byteBufferPool); - result = result.merge(generator.generateContent(13, 1024, ByteBuffer.wrap(largeContent).slice(), true, false)); + Generator.Result result = generator.generateContent(13, 1024, ByteBuffer.wrap(largeContent).slice(), true, false); final List frames = new ArrayList<>(); Parser parser = new Parser(new Parser.Listener.Adapter() diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java new file mode 100644 index 00000000000..9b070dceec3 --- /dev/null +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -0,0 +1,99 @@ +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Test; + +public class PriorityGenerateParseTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + @Test + public void testGenerateParse() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + int streamId = 13; + int dependentStreamId = 17; + int weight = 3; + boolean exclusive = true; + + // Iterate a few times to be sure generator and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + Generator.Result result = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onPriorityFrame(PriorityFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + } + + Assert.assertEquals(1, frames.size()); + PriorityFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertEquals(dependentStreamId, frame.getDependentStreamId()); + Assert.assertEquals(weight, frame.getWeight()); + Assert.assertEquals(exclusive, frame.isExclusive()); + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + int streamId = 13; + int dependentStreamId = 17; + int weight = 3; + boolean exclusive = true; + + final List frames = new ArrayList<>(); + Generator.Result result = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onPriorityFrame(PriorityFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(1, frames.size()); + PriorityFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertEquals(dependentStreamId, frame.getDependentStreamId()); + Assert.assertEquals(weight, frame.getWeight()); + Assert.assertEquals(exclusive, frame.isExclusive()); + } +} From 6f3f7f5334dd167c2a830b9eb5d10d305e1a4c49 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 5 Jun 2014 20:30:11 +0200 Subject: [PATCH 014/269] Implemented parser and generator for RST_STREAM frame. --- .../eclipse/jetty/http2/frames/FrameType.java | 2 +- .../jetty/http2/frames/ResetFrame.java | 41 +++++++++ .../jetty/http2/generator/Generator.java | 54 +++++++---- .../jetty/http2/parser/BodyParser.java | 14 +++ .../eclipse/jetty/http2/parser/Parser.java | 17 +++- .../http2/parser/PriorityBodyParser.java | 9 +- .../jetty/http2/parser/ResetBodyParser.java | 78 ++++++++++++++++ .../frames/PriorityGenerateParseTest.java | 1 - .../http2/frames/ResetGenerateParseTest.java | 90 +++++++++++++++++++ 9 files changed, 279 insertions(+), 27 deletions(-) create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java create mode 100644 jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java index e9c80df8200..7afb5f11290 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.http2.frames; public enum FrameType { - DATA(0), HEADERS(1), PRIORITY(2); + DATA(0), HEADERS(1), PRIORITY(2), RST_STREAM(3); private final int type; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java new file mode 100644 index 00000000000..3fa1343dfec --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java @@ -0,0 +1,41 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class ResetFrame +{ + private final int streamId; + private final int error; + + public ResetFrame(int streamId, int error) + { + this.streamId = streamId; + this.error = error; + } + + public int getStreamId() + { + return streamId; + } + + public int getError() + { + return error; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 2c5c6ff66ca..cad5fc82cd5 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -43,17 +43,9 @@ public class Generator if (dependentStreamId < 0) throw new IllegalArgumentException("Invalid dependent stream id: " + dependentStreamId); - ByteBuffer header = byteBufferPool.acquire(8 + 5, true); - BufferUtil.clearToFill(header); - Result result = new Result(byteBufferPool); - header.putShort((short)5); - header.put((byte)FrameType.PRIORITY.getType()); - // No flags. - header.put((byte)0); - - header.putInt(dependentStreamId); + ByteBuffer header = generateHeader(FrameType.PRIORITY, 5, 0, dependentStreamId); if (exclusive) streamId |= 0x80_00_00_00; @@ -68,6 +60,23 @@ public class Generator return result; } + public Result generateReset(int streamId, int error) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + + Result result = new Result(byteBufferPool); + + ByteBuffer header = generateHeader(FrameType.RST_STREAM, 4, 0, streamId); + + header.putInt(error); + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + + return result; + } + public Result generateContent(int streamId, int paddingLength, ByteBuffer data, boolean last, boolean compress) { if (streamId < 0) @@ -111,13 +120,7 @@ public class Generator private void generateFrame(Result result, int streamId, int paddingBytes, int paddingLength, ByteBuffer data, boolean last, boolean compress) { - ByteBuffer header = byteBufferPool.acquire(8 + paddingBytes, true); - BufferUtil.clearToFill(header); - int length = paddingBytes + data.remaining() + paddingLength; - header.putShort((short)length); - - header.put((byte)FrameType.DATA.getType()); int flags = 0; if (last) @@ -128,9 +131,8 @@ public class Generator flags |= 0x10; if (compress) flags |= 0x20; - header.put((byte)flags); - header.putInt(streamId); + ByteBuffer header = generateHeader(FrameType.DATA, 8 + paddingBytes, length, flags, streamId); if (paddingBytes == 2) header.putShort((short)paddingLength); @@ -152,6 +154,24 @@ public class Generator } } + private ByteBuffer generateHeader(FrameType frameType, int length, int flags, int streamId) + { + return generateHeader(frameType, 8 + length, length, flags, streamId); + } + + private ByteBuffer generateHeader(FrameType frameType, int capacity, int length, int flags, int streamId) + { + ByteBuffer header = byteBufferPool.acquire(capacity, true); + BufferUtil.clearToFill(header); + + header.putShort((short)length); + header.put((byte)frameType.getType()); + header.put((byte)flags); + header.putInt(streamId); + + return header; + } + public static class Result { private final ByteBufferPool byteBufferPool; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 85da726fef2..80a6946ff4f 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -96,6 +97,19 @@ public abstract class BodyParser } } + protected boolean notifyResetFrame(ResetFrame frame) + { + try + { + return listener.onResetFrame(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + public enum Result { PENDING, ASYNC, COMPLETE diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 21b0dbdc3db..9ac608a9b30 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -21,19 +21,22 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.PriorityFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; public class Parser { private final HeaderParser headerParser = new HeaderParser(); - private final BodyParser[] bodyParsers = new BodyParser[3]; + private final BodyParser[] bodyParsers = new BodyParser[4]; private State state = State.HEADER; private BodyParser bodyParser; public Parser(Listener listener) { - bodyParsers[0] = new DataBodyParser(headerParser, listener); - bodyParsers[2] = new PriorityBodyParser(headerParser, listener); + bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener); + bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); + bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); } private void reset() @@ -87,6 +90,8 @@ public class Parser public boolean onPriorityFrame(PriorityFrame frame); + public boolean onResetFrame(ResetFrame frame); + public static class Adapter implements Listener { @Override @@ -100,6 +105,12 @@ public class Parser { return false; } + + @Override + public boolean onResetFrame(ResetFrame frame) + { + return false; + } } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index 91968319a7b..2cee2de789a 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -92,9 +92,7 @@ public class PriorityBodyParser extends BodyParser case WEIGHT: { int weight = buffer.get() & 0xFF; - boolean async = onPriority(weight); - reset(); - return async ? Result.ASYNC : Result.COMPLETE; + return onPriority(weight); } default: { @@ -105,10 +103,11 @@ public class PriorityBodyParser extends BodyParser return Result.PENDING; } - private boolean onPriority(int weight) + private Result onPriority(int weight) { PriorityFrame frame = new PriorityFrame(streamId, getStreamId(), weight, exclusive); - return notifyPriorityFrame(frame); + reset(); + return notifyPriorityFrame(frame) ? Result.ASYNC : Result.COMPLETE; } private enum State diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java new file mode 100644 index 00000000000..4d8818b7c47 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java @@ -0,0 +1,78 @@ +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.ResetFrame; + +public class ResetBodyParser extends BodyParser +{ + private State state = State.ERROR; + private int cursor; + private int error; + + public ResetBodyParser(HeaderParser headerParser, Parser.Listener listener) + { + super(headerParser, listener); + } + + @Override + protected void reset() + { + super.reset(); + state = State.ERROR; + cursor = 0; + error = 0; + } + + @Override + public Result parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case ERROR: + { + if (buffer.remaining() >= 4) + { + return onReset(buffer.getInt()); + } + else + { + state = State.ERROR_BYTES; + cursor = 4; + } + break; + } + case ERROR_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + error += currByte << (8 * cursor); + if (cursor == 0) + { + return onReset(error); + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return Result.PENDING; + } + + private Result onReset(int error) + { + ResetFrame frame = new ResetFrame(getStreamId(), error); + reset(); + return notifyResetFrame(frame) ? Result.ASYNC : Result.COMPLETE; + } + + private enum State + { + ERROR, ERROR_BYTES + } +} diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index 9b070dceec3..81a2b458b34 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -80,7 +80,6 @@ public class PriorityGenerateParseTest } }); - frames.clear(); for (ByteBuffer buffer : result.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java new file mode 100644 index 00000000000..9857acdded7 --- /dev/null +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -0,0 +1,90 @@ +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Test; + +public class ResetGenerateParseTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + @Test + public void testGenerateParse() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + int streamId = 13; + int error = 17; + + // Iterate a few times to be sure generator and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + Generator.Result result = generator.generateReset(streamId, error); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onResetFrame(ResetFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + } + + Assert.assertEquals(1, frames.size()); + ResetFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertEquals(error, frame.getError()); + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + int streamId = 13; + int error = 17; + + final List frames = new ArrayList<>(); + Generator.Result result = generator.generateReset(streamId, error); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onResetFrame(ResetFrame frame) + { + frames.add(frame); + return false; + } + }); + + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(1, frames.size()); + ResetFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertEquals(error, frame.getError()); + } +} From 81538c9b5943b90cce1651fc324709a727b3dad0 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 5 Jun 2014 21:04:26 +0200 Subject: [PATCH 015/269] Implemented parser and generator for PING frame. --- .../eclipse/jetty/http2/frames/FrameType.java | 13 ++- .../eclipse/jetty/http2/frames/PingFrame.java | 41 +++++++ .../jetty/http2/generator/Generator.java | 14 +++ .../jetty/http2/parser/BodyParser.java | 31 ++++- .../jetty/http2/parser/HeaderParser.java | 14 +-- .../eclipse/jetty/http2/parser/Parser.java | 24 ++-- .../jetty/http2/parser/PingBodyParser.java | 97 ++++++++++++++++ .../http2/frames/DataGenerateParseTest.java | 4 +- .../http2/frames/PingGenerateParseTest.java | 109 ++++++++++++++++++ .../frames/PriorityGenerateParseTest.java | 4 +- .../http2/frames/ResetGenerateParseTest.java | 4 +- 11 files changed, 323 insertions(+), 32 deletions(-) create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java create mode 100644 jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java index 7afb5f11290..f46855d0eaa 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java @@ -20,7 +20,18 @@ package org.eclipse.jetty.http2.frames; public enum FrameType { - DATA(0), HEADERS(1), PRIORITY(2), RST_STREAM(3); + DATA(0), + HEADERS(1), + PRIORITY(2), + RST_STREAM(3), + SETTINGS(4), + PUSH_PROMISE(5), + PING(6), + GO_AWAY(7), + WINDOW_UPDATE(8), + CONTINUATION(9), + ALTSVC(10), + BLOCKED(11); private final int type; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java new file mode 100644 index 00000000000..575f63f0251 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java @@ -0,0 +1,41 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class PingFrame +{ + private final byte[] payload; + private final boolean reply; + + public PingFrame(byte[] payload, boolean reply) + { + this.payload = payload; + this.reply = reply; + } + + public byte[] getPayload() + { + return payload; + } + + public boolean isReply() + { + return reply; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index cad5fc82cd5..6cad0ee1e36 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -36,6 +36,20 @@ public class Generator this.byteBufferPool = byteBufferPool; } + public Result generatePing(byte[] payload, boolean reply) + { + Result result = new Result(byteBufferPool); + + ByteBuffer header = generateHeader(FrameType.PING, 8, reply ? 0x01 : 0x00, 0); + + header.put(payload); + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + + return result; + } + public Result generatePriority(int streamId, int dependentStreamId, int weight, boolean exclusive) { if (streamId < 0) diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 80a6946ff4f..a21ab91d1b8 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.util.log.Log; @@ -41,19 +42,24 @@ public abstract class BodyParser public abstract Result parse(ByteBuffer buffer); + protected boolean hasFlag(int bit) + { + return headerParser.hasFlag(bit); + } + protected boolean isPaddingHigh() { - return headerParser.isPaddingHigh(); + return headerParser.hasFlag(0x10); } protected boolean isPaddingLow() { - return headerParser.isPaddingLow(); + return headerParser.hasFlag(0x8); } protected boolean isEndStream() { - return headerParser.isEndStream(); + return headerParser.hasFlag(0x1); } protected int getStreamId() @@ -75,7 +81,7 @@ public abstract class BodyParser { try { - return listener.onDataFrame(frame); + return listener.onData(frame); } catch (Throwable x) { @@ -88,7 +94,7 @@ public abstract class BodyParser { try { - return listener.onPriorityFrame(frame); + return listener.onPriority(frame); } catch (Throwable x) { @@ -101,7 +107,20 @@ public abstract class BodyParser { try { - return listener.onResetFrame(frame); + return listener.onReset(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + + protected boolean notifyPingFrame(PingFrame frame) + { + try + { + return listener.onPing(frame); } catch (Throwable x) { diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java index 27e1bb9ac74..87d2a9750ae 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java @@ -121,19 +121,9 @@ public class HeaderParser return type; } - public boolean isPaddingHigh() + public boolean hasFlag(int bit) { - return (flags & 0x10) == 0x10; - } - - public boolean isPaddingLow() - { - return (flags & 0x08) == 0x08; - } - - public boolean isEndStream() - { - return (flags & 0x01) == 0x01; + return (flags & bit) == bit; } public int getStreamId() diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 9ac608a9b30..a213b461ae5 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -22,13 +22,14 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; public class Parser { private final HeaderParser headerParser = new HeaderParser(); - private final BodyParser[] bodyParsers = new BodyParser[4]; + private final BodyParser[] bodyParsers = new BodyParser[FrameType.values().length]; private State state = State.HEADER; private BodyParser bodyParser; @@ -37,6 +38,7 @@ public class Parser bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener); bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); + bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener); } private void reset() @@ -86,28 +88,36 @@ public class Parser public interface Listener { - public boolean onDataFrame(DataFrame frame); + public boolean onData(DataFrame frame); - public boolean onPriorityFrame(PriorityFrame frame); + public boolean onPriority(PriorityFrame frame); - public boolean onResetFrame(ResetFrame frame); + public boolean onReset(ResetFrame frame); + + public boolean onPing(PingFrame frame); public static class Adapter implements Listener { @Override - public boolean onDataFrame(DataFrame frame) + public boolean onData(DataFrame frame) { return false; } @Override - public boolean onPriorityFrame(PriorityFrame frame) + public boolean onPriority(PriorityFrame frame) { return false; } @Override - public boolean onResetFrame(ResetFrame frame) + public boolean onReset(ResetFrame frame) + { + return false; + } + + @Override + public boolean onPing(PingFrame frame) { return false; } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java new file mode 100644 index 00000000000..4fad4161513 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -0,0 +1,97 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.PingFrame; + +public class PingBodyParser extends BodyParser +{ + private State state = State.PAYLOAD; + private int cursor; + private byte[] payload; + + public PingBodyParser(HeaderParser headerParser, Parser.Listener listener) + { + super(headerParser, listener); + } + + @Override + protected void reset() + { + super.reset(); + state = State.PAYLOAD; + cursor = 0; + payload = null; + } + + @Override + public Result parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case PAYLOAD: + { + payload = new byte[8]; + if (buffer.remaining() >= 8) + { + buffer.get(payload); + return onPing(payload); + } + else + { + state = State.PAYLOAD_BYTES; + cursor = 8; + } + break; + } + case PAYLOAD_BYTES: + { + payload[8 - cursor] = buffer.get(); + --cursor; + if (cursor == 0) + { + return onPing(payload); + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return Result.PENDING; + } + + private Result onPing(byte[] payload) + { + PingFrame frame = new PingFrame(payload, hasFlag(0x1)); + reset(); + return notifyPingFrame(frame) ? Result.ASYNC : Result.COMPLETE; + } + + private enum State + { + PAYLOAD, PAYLOAD_BYTES + } +} diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index d138fb5de8d..34e89f527bc 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -124,7 +124,7 @@ public class DataGenerateParseTest Parser parser = new Parser(new Parser.Listener.Adapter() { @Override - public boolean onDataFrame(DataFrame frame) + public boolean onData(DataFrame frame) { frames.add(frame); return false; @@ -152,7 +152,7 @@ public class DataGenerateParseTest Parser parser = new Parser(new Parser.Listener.Adapter() { @Override - public boolean onDataFrame(DataFrame frame) + public boolean onData(DataFrame frame) { frames.add(frame); return false; diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java new file mode 100644 index 00000000000..63f2b0adf21 --- /dev/null +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -0,0 +1,109 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Test; + +public class PingGenerateParseTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + @Test + public void testGenerateParse() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + byte[] payload = new byte[8]; + new Random().nextBytes(payload); + + // Iterate a few times to be sure generator and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + Generator.Result result = generator.generatePing(payload, true); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onPing(PingFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + } + + Assert.assertEquals(1, frames.size()); + PingFrame frame = frames.get(0); + Assert.assertArrayEquals(payload, frame.getPayload()); + Assert.assertTrue(frame.isReply()); + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + byte[] payload = new byte[8]; + new Random().nextBytes(payload); + + final List frames = new ArrayList<>(); + Generator.Result result = generator.generatePing(payload, true); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onPing(PingFrame frame) + { + frames.add(frame); + return false; + } + }); + + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(1, frames.size()); + PingFrame frame = frames.get(0); + Assert.assertArrayEquals(payload, frame.getPayload()); + Assert.assertTrue(frame.isReply()); + } +} diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index 81a2b458b34..4bda261b226 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -33,7 +33,7 @@ public class PriorityGenerateParseTest Parser parser = new Parser(new Parser.Listener.Adapter() { @Override - public boolean onPriorityFrame(PriorityFrame frame) + public boolean onPriority(PriorityFrame frame) { frames.add(frame); return false; @@ -73,7 +73,7 @@ public class PriorityGenerateParseTest Parser parser = new Parser(new Parser.Listener.Adapter() { @Override - public boolean onPriorityFrame(PriorityFrame frame) + public boolean onPriority(PriorityFrame frame) { frames.add(frame); return false; diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index 9857acdded7..bca71b45aa8 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -31,7 +31,7 @@ public class ResetGenerateParseTest Parser parser = new Parser(new Parser.Listener.Adapter() { @Override - public boolean onResetFrame(ResetFrame frame) + public boolean onReset(ResetFrame frame) { frames.add(frame); return false; @@ -67,7 +67,7 @@ public class ResetGenerateParseTest Parser parser = new Parser(new Parser.Listener.Adapter() { @Override - public boolean onResetFrame(ResetFrame frame) + public boolean onReset(ResetFrame frame) { frames.add(frame); return false; From 7a347e267fdf57828f56195a719021450bf22a4f Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 5 Jun 2014 22:28:39 +0200 Subject: [PATCH 016/269] Implemented parser and generator for GO_AWAY frame. --- .../jetty/http2/frames/GoAwayFrame.java | 48 +++++ .../jetty/http2/generator/Generator.java | 35 +++- .../jetty/http2/parser/BodyParser.java | 22 ++- .../jetty/http2/parser/DataBodyParser.java | 2 +- .../jetty/http2/parser/GoAwayBodyParser.java | 166 ++++++++++++++++++ .../eclipse/jetty/http2/parser/Parser.java | 10 ++ .../jetty/http2/parser/PingBodyParser.java | 2 +- .../http2/parser/PriorityBodyParser.java | 6 +- .../jetty/http2/parser/ResetBodyParser.java | 20 ++- .../http2/frames/DataGenerateParseTest.java | 4 +- .../http2/frames/GoAwayGenerateParseTest.java | 113 ++++++++++++ .../frames/PriorityGenerateParseTest.java | 18 ++ .../http2/frames/ResetGenerateParseTest.java | 18 ++ 13 files changed, 448 insertions(+), 16 deletions(-) create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java create mode 100644 jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java new file mode 100644 index 00000000000..d17d357de36 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java @@ -0,0 +1,48 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class GoAwayFrame +{ + private final int lastStreamId; + private final int error; + private final byte[] payload; + + public GoAwayFrame(int lastStreamId, int error, byte[] payload) + { + this.lastStreamId = lastStreamId; + this.error = error; + this.payload = payload; + } + + public int getLastStreamId() + { + return lastStreamId; + } + + public int getError() + { + return error; + } + + public byte[] getPayload() + { + return payload; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 6cad0ee1e36..7c4ea0abb98 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -36,8 +36,35 @@ public class Generator this.byteBufferPool = byteBufferPool; } + public Result generateGoAway(int lastStreamId, int error, byte[] payload) + { + if (lastStreamId < 0) + throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId); + + Result result = new Result(byteBufferPool); + + int length = 4 + 4 + (payload != null ? payload.length : 0); + ByteBuffer header = generateHeader(FrameType.GO_AWAY, length, 0, 0); + + header.putInt(lastStreamId); + header.putInt(error); + + if (payload != null) + { + header.put(payload); + } + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + + return result; + } + public Result generatePing(byte[] payload, boolean reply) { + if (payload.length != 8) + throw new IllegalArgumentException("Invalid payload length: " + payload.length); + Result result = new Result(byteBufferPool); ByteBuffer header = generateHeader(FrameType.PING, 8, reply ? 0x01 : 0x00, 0); @@ -91,7 +118,7 @@ public class Generator return result; } - public Result generateContent(int streamId, int paddingLength, ByteBuffer data, boolean last, boolean compress) + public Result generateData(int streamId, int paddingLength, ByteBuffer data, boolean last, boolean compress) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); @@ -110,7 +137,7 @@ public class Generator // Can we fit just one frame ? if (dataLength + paddingBytes + paddingLength <= DataFrame.MAX_LENGTH) { - generateFrame(result, streamId, paddingBytes, paddingLength, data, last, compress); + generateData(result, streamId, paddingBytes, paddingLength, data, last, compress); } else { @@ -126,13 +153,13 @@ public class Generator data.limit(Math.min(dataBytesPerFrame * i, limit)); ByteBuffer slice = data.slice(); data.position(data.limit()); - generateFrame(result, streamId, paddingBytes, paddingLength, slice, i == frames && last, compress); + generateData(result, streamId, paddingBytes, paddingLength, slice, i == frames && last, compress); } } return result; } - private void generateFrame(Result result, int streamId, int paddingBytes, int paddingLength, ByteBuffer data, boolean last, boolean compress) + private void generateData(Result result, int streamId, int paddingBytes, int paddingLength, ByteBuffer data, boolean last, boolean compress) { int length = paddingBytes + data.remaining() + paddingLength; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index a21ab91d1b8..34c158014c4 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; @@ -77,7 +78,7 @@ public abstract class BodyParser headerParser.reset(); } - protected boolean notifyDataFrame(DataFrame frame) + protected boolean notifyData(DataFrame frame) { try { @@ -90,7 +91,7 @@ public abstract class BodyParser } } - protected boolean notifyPriorityFrame(PriorityFrame frame) + protected boolean notifyPriority(PriorityFrame frame) { try { @@ -103,7 +104,7 @@ public abstract class BodyParser } } - protected boolean notifyResetFrame(ResetFrame frame) + protected boolean notifyReset(ResetFrame frame) { try { @@ -116,7 +117,7 @@ public abstract class BodyParser } } - protected boolean notifyPingFrame(PingFrame frame) + protected boolean notifyPing(PingFrame frame) { try { @@ -129,6 +130,19 @@ public abstract class BodyParser } } + protected boolean notifyGoAway(GoAwayFrame frame) + { + try + { + return listener.onGoAway(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + public enum Result { PENDING, ASYNC, COMPLETE diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index 5bd3d46cff7..781794b5100 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -135,7 +135,7 @@ public class DataBodyParser extends BodyParser { boolean end = isEndStream(); DataFrame frame = new DataFrame(getStreamId(), buffer, fragment ? false : end); - return notifyDataFrame(frame); + return notifyData(frame); } private enum State diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java new file mode 100644 index 00000000000..0d6ecf17f62 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java @@ -0,0 +1,166 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.GoAwayFrame; + +public class GoAwayBodyParser extends BodyParser +{ + private State state = State.LAST_STREAM_ID; + private int cursor; + + private int lastStreamId; + private int error; + private byte[] payload; + + public GoAwayBodyParser(HeaderParser headerParser, Parser.Listener listener) + { + super(headerParser, listener); + } + + @Override + protected void reset() + { + super.reset(); + state = State.LAST_STREAM_ID; + cursor = 0; + + lastStreamId = 0; + error = 0; + payload = null; + } + + @Override + public Result parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case LAST_STREAM_ID: + { + if (buffer.remaining() >= 4) + { + lastStreamId = buffer.getInt(); + lastStreamId &= 0x7F_FF_FF_FF; + state = State.ERROR; + } + else + { + state = State.LAST_STREAM_ID_BYTES; + cursor = 4; + } + break; + } + case LAST_STREAM_ID_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + lastStreamId += currByte << (8 * cursor); + if (cursor == 0) + { + lastStreamId &= 0x7F_FF_FF_FF; + state = State.ERROR; + } + break; + } + case ERROR: + { + if (buffer.remaining() >= 4) + { + error = buffer.getInt(); + state = State.PAYLOAD; + int payloadLength = getBodyLength() - 4 - 4; + if (payloadLength == 0) + { + return onGoAway(lastStreamId, error, null); + } + } + else + { + state = State.ERROR_BYTES; + cursor = 4; + } + break; + } + case ERROR_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + error += currByte << (8 * cursor); + if (cursor == 0) + { + state = State.PAYLOAD; + int payloadLength = getBodyLength() - 4 - 4; + if (payloadLength == 0) + { + return onGoAway(lastStreamId, error, null); + } + } + break; + } + case PAYLOAD: + { + int payloadLength = getBodyLength() - 4 - 4; + payload = new byte[payloadLength]; + if (buffer.remaining() >= payloadLength) + { + buffer.get(payload); + return onGoAway(lastStreamId, error, payload); + } + else + { + state = State.PAYLOAD_BYTES; + cursor = payloadLength; + } + break; + } + case PAYLOAD_BYTES: + { + payload[payload.length - cursor] = buffer.get(); + --cursor; + if (cursor == 0) + { + return onGoAway(lastStreamId, error, payload); + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return Result.PENDING; + } + + private Result onGoAway(int lastStreamId, int error, byte[] payload) + { + GoAwayFrame frame = new GoAwayFrame(lastStreamId, error, payload); + reset(); + return notifyGoAway(frame) ? Result.ASYNC : Result.COMPLETE; + } + + private enum State + { + LAST_STREAM_ID, LAST_STREAM_ID_BYTES, ERROR, ERROR_BYTES, PAYLOAD, PAYLOAD_BYTES + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index a213b461ae5..dbc38198ec3 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; @@ -39,6 +40,7 @@ public class Parser bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener); + bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener); } private void reset() @@ -96,6 +98,8 @@ public class Parser public boolean onPing(PingFrame frame); + public boolean onGoAway(GoAwayFrame frame); + public static class Adapter implements Listener { @Override @@ -121,6 +125,12 @@ public class Parser { return false; } + + @Override + public boolean onGoAway(GoAwayFrame frame) + { + return false; + } } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 4fad4161513..262a79975b3 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -87,7 +87,7 @@ public class PingBodyParser extends BodyParser { PingFrame frame = new PingFrame(payload, hasFlag(0x1)); reset(); - return notifyPingFrame(frame) ? Result.ASYNC : Result.COMPLETE; + return notifyPing(frame) ? Result.ASYNC : Result.COMPLETE; } private enum State diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index 2cee2de789a..b56574a063f 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -92,7 +92,7 @@ public class PriorityBodyParser extends BodyParser case WEIGHT: { int weight = buffer.get() & 0xFF; - return onPriority(weight); + return onPriority(streamId, weight, exclusive); } default: { @@ -103,11 +103,11 @@ public class PriorityBodyParser extends BodyParser return Result.PENDING; } - private Result onPriority(int weight) + private Result onPriority(int streamId, int weight, boolean exclusive) { PriorityFrame frame = new PriorityFrame(streamId, getStreamId(), weight, exclusive); reset(); - return notifyPriorityFrame(frame) ? Result.ASYNC : Result.COMPLETE; + return notifyPriority(frame) ? Result.ASYNC : Result.COMPLETE; } private enum State diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java index 4d8818b7c47..d9fed1d3716 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java @@ -1,3 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; @@ -68,7 +86,7 @@ public class ResetBodyParser extends BodyParser { ResetFrame frame = new ResetFrame(getStreamId(), error); reset(); - return notifyResetFrame(frame) ? Result.ASYNC : Result.COMPLETE; + return notifyReset(frame) ? Result.ASYNC : Result.COMPLETE; } private enum State diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 34e89f527bc..4670f3fffe7 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -118,7 +118,7 @@ public class DataGenerateParseTest Generator.Result result = new Generator.Result(byteBufferPool); for (int j = 1; j <= data.length; ++j) { - result = result.merge(generator.generateContent(13, paddingLength, data[j - 1].slice(), j == data.length, false)); + result = result.merge(generator.generateData(13, paddingLength, data[j - 1].slice(), j == data.length, false)); } Parser parser = new Parser(new Parser.Listener.Adapter() @@ -146,7 +146,7 @@ public class DataGenerateParseTest { Generator generator = new Generator(byteBufferPool); - Generator.Result result = generator.generateContent(13, 1024, ByteBuffer.wrap(largeContent).slice(), true, false); + Generator.Result result = generator.generateData(13, 1024, ByteBuffer.wrap(largeContent).slice(), true, false); final List frames = new ArrayList<>(); Parser parser = new Parser(new Parser.Listener.Adapter() diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java new file mode 100644 index 00000000000..dfc363d1ed6 --- /dev/null +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java @@ -0,0 +1,113 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Test; + +public class GoAwayGenerateParseTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + @Test + public void testGenerateParse() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + int lastStreamId = 13; + int error = 17; + + // Iterate a few times to be sure generator and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + Generator.Result result = generator.generateGoAway(lastStreamId, error, null); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onGoAway(GoAwayFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + } + + Assert.assertEquals(1, frames.size()); + GoAwayFrame frame = frames.get(0); + Assert.assertEquals(lastStreamId, frame.getLastStreamId()); + Assert.assertEquals(error, frame.getError()); + Assert.assertNull(frame.getPayload()); + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + int lastStreamId = 13; + int error = 17; + byte[] payload = new byte[16]; + new Random().nextBytes(payload); + + final List frames = new ArrayList<>(); + Generator.Result result = generator.generateGoAway(lastStreamId, error, payload); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onGoAway(GoAwayFrame frame) + { + frames.add(frame); + return false; + } + }); + + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(1, frames.size()); + GoAwayFrame frame = frames.get(0); + Assert.assertEquals(lastStreamId, frame.getLastStreamId()); + Assert.assertEquals(error, frame.getError()); + Assert.assertArrayEquals(payload, frame.getPayload()); + } +} diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index 4bda261b226..dcffe449e6a 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -1,3 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + package org.eclipse.jetty.http2.frames; import java.nio.ByteBuffer; diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index bca71b45aa8..2f946031466 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -1,3 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + package org.eclipse.jetty.http2.frames; import java.nio.ByteBuffer; From 54577057bbb8a8f19dec264d65d01d47c52583ef Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 6 Jun 2014 09:21:47 +0200 Subject: [PATCH 017/269] Implemented parser and generator for WINDOW_UPDATE frame. --- .../jetty/http2/frames/WindowUpdateFrame.java | 41 +++++ .../jetty/http2/generator/Generator.java | 147 ++++++++++-------- .../jetty/http2/parser/BodyParser.java | 14 ++ .../eclipse/jetty/http2/parser/Parser.java | 10 ++ .../http2/parser/WindowUpdateBodyParser.java | 98 ++++++++++++ .../frames/WindowUpdateGenerateParseTest.java | 108 +++++++++++++ 6 files changed, 354 insertions(+), 64 deletions(-) create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java create mode 100644 jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java new file mode 100644 index 00000000000..0ed4ac35dbe --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java @@ -0,0 +1,41 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class WindowUpdateFrame +{ + private final int streamId; + private final int windowDelta; + + public WindowUpdateFrame(int streamId, int windowDelta) + { + this.streamId = streamId; + this.windowDelta = windowDelta; + } + + public int getStreamId() + { + return streamId; + } + + public int getWindowDelta() + { + return windowDelta; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 7c4ea0abb98..587ee4a19f2 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -36,44 +36,44 @@ public class Generator this.byteBufferPool = byteBufferPool; } - public Result generateGoAway(int lastStreamId, int error, byte[] payload) + public Result generateData(int streamId, int paddingLength, ByteBuffer data, boolean last, boolean compress) { - if (lastStreamId < 0) - throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId); + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + // Leave space for at least one byte of content. + if (paddingLength > DataFrame.MAX_LENGTH - 3) + throw new IllegalArgumentException("Invalid padding length: " + paddingLength); + + int paddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; + + // TODO: here we should compress the data, and then reason on the data length ! + + int dataLength = data.remaining(); Result result = new Result(byteBufferPool); - int length = 4 + 4 + (payload != null ? payload.length : 0); - ByteBuffer header = generateHeader(FrameType.GO_AWAY, length, 0, 0); - - header.putInt(lastStreamId); - header.putInt(error); - - if (payload != null) + // Can we fit just one frame ? + if (dataLength + paddingBytes + paddingLength <= DataFrame.MAX_LENGTH) { - header.put(payload); + generateData(result, streamId, paddingBytes, paddingLength, data, last, compress); + } + else + { + int dataBytesPerFrame = DataFrame.MAX_LENGTH - paddingBytes - paddingLength; + int frames = dataLength / dataBytesPerFrame; + if (frames * dataBytesPerFrame != dataLength) + { + ++frames; + } + int limit = data.limit(); + for (int i = 1; i <= frames; ++i) + { + data.limit(Math.min(dataBytesPerFrame * i, limit)); + ByteBuffer slice = data.slice(); + data.position(data.limit()); + generateData(result, streamId, paddingBytes, paddingLength, slice, i == frames && last, compress); + } } - - BufferUtil.flipToFlush(header, 0); - result.add(header, true); - - return result; - } - - public Result generatePing(byte[] payload, boolean reply) - { - if (payload.length != 8) - throw new IllegalArgumentException("Invalid payload length: " + payload.length); - - Result result = new Result(byteBufferPool); - - ByteBuffer header = generateHeader(FrameType.PING, 8, reply ? 0x01 : 0x00, 0); - - header.put(payload); - - BufferUtil.flipToFlush(header, 0); - result.add(header, true); - return result; } @@ -118,44 +118,63 @@ public class Generator return result; } - public Result generateData(int streamId, int paddingLength, ByteBuffer data, boolean last, boolean compress) + public Result generatePing(byte[] payload, boolean reply) { - if (streamId < 0) - throw new IllegalArgumentException("Invalid stream id: " + streamId); - // Leave space for at least one byte of content. - if (paddingLength > DataFrame.MAX_LENGTH - 3) - throw new IllegalArgumentException("Invalid padding length: " + paddingLength); - - int paddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; - - // TODO: here we should compress the data, and then reason on the data length ! - - int dataLength = data.remaining(); + if (payload.length != 8) + throw new IllegalArgumentException("Invalid payload length: " + payload.length); Result result = new Result(byteBufferPool); - // Can we fit just one frame ? - if (dataLength + paddingBytes + paddingLength <= DataFrame.MAX_LENGTH) + ByteBuffer header = generateHeader(FrameType.PING, 8, reply ? 0x01 : 0x00, 0); + + header.put(payload); + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + + return result; + } + + public Result generateGoAway(int lastStreamId, int error, byte[] payload) + { + if (lastStreamId < 0) + throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId); + + Result result = new Result(byteBufferPool); + + int length = 4 + 4 + (payload != null ? payload.length : 0); + ByteBuffer header = generateHeader(FrameType.GO_AWAY, length, 0, 0); + + header.putInt(lastStreamId); + header.putInt(error); + + if (payload != null) { - generateData(result, streamId, paddingBytes, paddingLength, data, last, compress); - } - else - { - int dataBytesPerFrame = DataFrame.MAX_LENGTH - paddingBytes - paddingLength; - int frames = dataLength / dataBytesPerFrame; - if (frames * dataBytesPerFrame != dataLength) - { - ++frames; - } - int limit = data.limit(); - for (int i = 1; i <= frames; ++i) - { - data.limit(Math.min(dataBytesPerFrame * i, limit)); - ByteBuffer slice = data.slice(); - data.position(data.limit()); - generateData(result, streamId, paddingBytes, paddingLength, slice, i == frames && last, compress); - } + header.put(payload); } + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + + return result; + } + + public Result generateWindowUpdate(int streamId, int windowUpdate) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + if (windowUpdate < 0) + throw new IllegalArgumentException("Invalid window update: " + windowUpdate); + + Result result = new Result(byteBufferPool); + + ByteBuffer header = generateHeader(FrameType.WINDOW_UPDATE, 4, 0, streamId); + + header.putInt(windowUpdate); + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + return result; } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 34c158014c4..09630c685b5 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -25,6 +25,7 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -143,6 +144,19 @@ public abstract class BodyParser } } + protected boolean notifyWindowUpdate(WindowUpdateFrame frame) + { + try + { + return listener.onWindowUpdate(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + public enum Result { PENDING, ASYNC, COMPLETE diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index dbc38198ec3..fa6ff4cb956 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; public class Parser { @@ -41,6 +42,7 @@ public class Parser bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener); bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener); + bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener); } private void reset() @@ -100,6 +102,8 @@ public class Parser public boolean onGoAway(GoAwayFrame frame); + public boolean onWindowUpdate(WindowUpdateFrame frame); + public static class Adapter implements Listener { @Override @@ -131,6 +135,12 @@ public class Parser { return false; } + + @Override + public boolean onWindowUpdate(WindowUpdateFrame frame) + { + return false; + } } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java new file mode 100644 index 00000000000..b651c9d392a --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java @@ -0,0 +1,98 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; + +public class WindowUpdateBodyParser extends BodyParser +{ + private State state = State.WINDOW_DELTA; + private int cursor; + private int windowDelta; + + public WindowUpdateBodyParser(HeaderParser headerParser, Parser.Listener listener) + { + super(headerParser, listener); + } + + @Override + protected void reset() + { + super.reset(); + state = State.WINDOW_DELTA; + cursor = 0; + windowDelta = 0; + } + + @Override + public Result parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case WINDOW_DELTA: + { + if (buffer.remaining() >= 4) + { + windowDelta = buffer.getInt() & 0x7F_FF_FF_FF; + return onWindowUpdate(windowDelta); + } + else + { + state = State.WINDOW_DELTA_BYTES; + cursor = 4; + } + break; + } + case WINDOW_DELTA_BYTES: + { + byte currByte = buffer.get(); + --cursor; + windowDelta += (currByte & 0xFF) << 8 * cursor; + if (cursor == 0) + { + windowDelta &= 0x7F_FF_FF_FF; + return onWindowUpdate(windowDelta); + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return Result.PENDING; + } + + private Result onWindowUpdate(int windowDelta) + { + WindowUpdateFrame frame = new WindowUpdateFrame(getStreamId(), windowDelta); + reset(); + return notifyWindowUpdate(frame) ? Result.ASYNC : Result.COMPLETE; + } + + private enum State + { + WINDOW_DELTA, WINDOW_DELTA_BYTES + } +} diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java new file mode 100644 index 00000000000..cfb9816af6e --- /dev/null +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java @@ -0,0 +1,108 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Test; + +public class WindowUpdateGenerateParseTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + @Test + public void testGenerateParse() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + int streamId = 13; + int windowUpdate = 17; + + // Iterate a few times to be sure generator and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + Generator.Result result = generator.generateWindowUpdate(streamId, windowUpdate); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onWindowUpdate(WindowUpdateFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + } + + Assert.assertEquals(1, frames.size()); + WindowUpdateFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertEquals(windowUpdate, frame.getWindowDelta()); + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + int streamId = 13; + int windowUpdate = 17; + + final List frames = new ArrayList<>(); + Generator.Result result = generator.generateWindowUpdate(streamId, windowUpdate); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onWindowUpdate(WindowUpdateFrame frame) + { + frames.add(frame); + return false; + } + }); + + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(1, frames.size()); + WindowUpdateFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertEquals(windowUpdate, frame.getWindowDelta()); + } +} From 2a485be6c13e5f84df80c77299d239cefd932311 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 6 Jun 2014 11:23:50 +0200 Subject: [PATCH 018/269] Implemented parser and generator for SETTINGS frame. --- .../jetty/http2/frames/SettingsFrame.java | 43 +++++ .../jetty/http2/generator/Generator.java | 19 ++ .../jetty/http2/parser/BodyParser.java | 39 +++- .../jetty/http2/parser/DataBodyParser.java | 14 +- .../eclipse/jetty/http2/parser/ErrorCode.java | 36 ++++ .../jetty/http2/parser/GoAwayBodyParser.java | 6 +- .../jetty/http2/parser/HeaderParser.java | 8 + .../eclipse/jetty/http2/parser/Parser.java | 93 ++++++++-- .../jetty/http2/parser/PingBodyParser.java | 4 +- .../http2/parser/PriorityBodyParser.java | 6 +- .../jetty/http2/parser/ResetBodyParser.java | 4 +- .../http2/parser/SettingsBodyParser.java | 148 +++++++++++++++ .../http2/parser/WindowUpdateBodyParser.java | 4 +- .../http2/frames/DataGenerateParseTest.java | 13 ++ .../frames/SettingsGenerateParseTest.java | 171 ++++++++++++++++++ 15 files changed, 564 insertions(+), 44 deletions(-) create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java create mode 100644 jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java new file mode 100644 index 00000000000..5fe64b0a863 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -0,0 +1,43 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import java.util.Map; + +public class SettingsFrame +{ + private final Map settings; + private final boolean reply; + + public SettingsFrame(Map settings, boolean reply) + { + this.settings = settings; + this.reply = reply; + } + + public Map getSettings() + { + return settings; + } + + public boolean isReply() + { + return reply; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 587ee4a19f2..daedce95c2e 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.FrameType; @@ -118,6 +119,24 @@ public class Generator return result; } + public Result generateSettings(Map settings, boolean reply) + { + Result result = new Result(byteBufferPool); + + ByteBuffer header = generateHeader(FrameType.SETTINGS, 5 * settings.size(), reply ? 0x01 : 0x00, 0); + + for (Map.Entry entry : settings.entrySet()) + { + header.put(entry.getKey().byteValue()); + header.putInt(entry.getValue()); + } + + BufferUtil.flipToFlush(header, 0); + result.add(header, true); + + return result; + } + public Result generatePing(byte[] payload, boolean reply) { if (payload.length != 8) diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 09630c685b5..1d9040c152f 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -25,6 +25,7 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -44,6 +45,12 @@ public abstract class BodyParser public abstract Result parse(ByteBuffer buffer); + protected boolean emptyBody() + { + notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_frame"); + return false; + } + protected boolean hasFlag(int bit) { return headerParser.hasFlag(bit); @@ -74,11 +81,6 @@ public abstract class BodyParser return headerParser.getLength(); } - protected void reset() - { - headerParser.reset(); - } - protected boolean notifyData(DataFrame frame) { try @@ -118,6 +120,19 @@ public abstract class BodyParser } } + protected boolean notifySettings(SettingsFrame frame) + { + try + { + return listener.onSettings(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + protected boolean notifyPing(PingFrame frame) { try @@ -157,6 +172,20 @@ public abstract class BodyParser } } + protected Result notifyConnectionFailure(int error, String reason) + { + try + { + listener.onConnectionFailure(error, reason); + return Result.ASYNC; + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return Result.ASYNC; + } + } + public enum Result { PENDING, ASYNC, COMPLETE diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index 781794b5100..f230d651d09 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.util.BufferUtil; public class DataBodyParser extends BodyParser { @@ -33,15 +34,19 @@ public class DataBodyParser extends BodyParser super(headerParser, listener); } - @Override - protected void reset() + private void reset() { - super.reset(); state = State.PREPARE; paddingLength = 0; length = 0; } + @Override + protected boolean emptyBody() + { + return onData(BufferUtil.EMPTY_BUFFER, false); + } + @Override public Result parse(ByteBuffer buffer) { @@ -133,8 +138,7 @@ public class DataBodyParser extends BodyParser private boolean onData(ByteBuffer buffer, boolean fragment) { - boolean end = isEndStream(); - DataFrame frame = new DataFrame(getStreamId(), buffer, fragment ? false : end); + DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream()); return notifyData(frame); } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java new file mode 100644 index 00000000000..b94a19b8764 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java @@ -0,0 +1,36 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +public interface ErrorCode +{ + public static final int NO_ERROR = 0; + public static final int PROTOCOL_ERROR = 1; + public static final int INTERNAL_ERROR = 2; + public static final int FLOW_CONTROL_ERROR = 3; + public static final int SETTINGS_TIMEOUT_ERROR = 4; + public static final int STREAM_CLOSED_ERROR = 5; + public static final int FRAME_SIZE_ERROR = 6; + public static final int REFUSED_STREAM_ERROR = 7; + public static final int CANCEL_STREAM_ERROR = 8; + public static final int COMPRESSION_ERROR = 9; + public static final int HTTP_CONNECT_ERROR = 10; + public static final int ENHANCE_YOUR_CALM_ERROR = 11; + public static final int INADEQUATE_SECURITY_ERROR = 12; +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java index 0d6ecf17f62..45671bc6969 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java @@ -26,7 +26,6 @@ public class GoAwayBodyParser extends BodyParser { private State state = State.LAST_STREAM_ID; private int cursor; - private int lastStreamId; private int error; private byte[] payload; @@ -36,13 +35,10 @@ public class GoAwayBodyParser extends BodyParser super(headerParser, listener); } - @Override - protected void reset() + private void reset() { - super.reset(); state = State.LAST_STREAM_ID; cursor = 0; - lastStreamId = 0; error = 0; payload = null; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java index 87d2a9750ae..fe72e1c2962 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java @@ -43,6 +43,14 @@ public class HeaderParser streamId = 0; } + /** + * Parses the header bytes in the given {@code buffer}; only the header + * bytes are consumed, therefore the buffer may contain unconsumed bytes. + * + * @param buffer the buffer to parse + * @return true if a whole header was parsed, false if not enough header + * bytes were present in the buffer + */ public boolean parse(ByteBuffer buffer) { while (buffer.hasRemaining()) diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index fa6ff4cb956..01281c21bca 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -26,20 +26,27 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class Parser { + private static final Logger LOG = Log.getLogger(Parser.class); + private final HeaderParser headerParser = new HeaderParser(); private final BodyParser[] bodyParsers = new BodyParser[FrameType.values().length]; + private final Listener listener; private State state = State.HEADER; - private BodyParser bodyParser; public Parser(Listener listener) { + this.listener = listener; bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener); bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); + bodyParsers[FrameType.SETTINGS.getType()] = new SettingsBodyParser(headerParser, listener); bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener); bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener); bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener); @@ -47,37 +54,67 @@ public class Parser private void reset() { + headerParser.reset(); state = State.HEADER; } public boolean parse(ByteBuffer buffer) { - while (buffer.hasRemaining()) + while (true) { switch (state) { case HEADER: { - if (headerParser.parse(buffer)) - { - int type = headerParser.getFrameType(); - bodyParser = bodyParsers[type]; - state = State.BODY; - } + if (!headerParser.parse(buffer)) + return false; + state = State.BODY; break; } case BODY: { - BodyParser.Result result = bodyParser.parse(buffer); - if (result == BodyParser.Result.ASYNC) + int type = headerParser.getFrameType(); + if (type < 0 || type >= bodyParsers.length) { - // The content will be processed asynchronously, stop parsing; - // the asynchronous operation will eventually resume parsing. - return true; + notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "unknown_frame_type_" + type); + return false; } - else if (result == BodyParser.Result.COMPLETE) + BodyParser bodyParser = bodyParsers[type]; + if (headerParser.getLength() == 0) { + boolean async = bodyParser.emptyBody(); reset(); + if (async) + return true; + if (!buffer.hasRemaining()) + return false; + } + else + { + BodyParser.Result result = bodyParser.parse(buffer); + switch (result) + { + case PENDING: + { + // Not enough bytes. + return false; + } + case ASYNC: + { + // The content will be processed asynchronously, stop parsing; + // the asynchronous operation will eventually resume parsing. + return true; + } + case COMPLETE: + { + reset(); + break; + } + default: + { + throw new IllegalStateException(); + } + } } break; } @@ -87,7 +124,18 @@ public class Parser } } } - return false; + } + + protected void notifyConnectionFailure(int error, String reason) + { + try + { + listener.onConnectionFailure(error, reason); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } } public interface Listener @@ -98,12 +146,16 @@ public class Parser public boolean onReset(ResetFrame frame); + public boolean onSettings(SettingsFrame frame); + public boolean onPing(PingFrame frame); public boolean onGoAway(GoAwayFrame frame); public boolean onWindowUpdate(WindowUpdateFrame frame); + public void onConnectionFailure(int error, String reason); + public static class Adapter implements Listener { @Override @@ -124,6 +176,12 @@ public class Parser return false; } + @Override + public boolean onSettings(SettingsFrame frame) + { + return false; + } + @Override public boolean onPing(PingFrame frame) { @@ -141,6 +199,11 @@ public class Parser { return false; } + + @Override + public void onConnectionFailure(int error, String reason) + { + } } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 262a79975b3..173a5ea57b0 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -33,10 +33,8 @@ public class PingBodyParser extends BodyParser super(headerParser, listener); } - @Override - protected void reset() + private void reset() { - super.reset(); state = State.PAYLOAD; cursor = 0; payload = null; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index b56574a063f..e37785e0739 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -26,7 +26,6 @@ public class PriorityBodyParser extends BodyParser { private State state = State.EXCLUSIVE; private int cursor; - private boolean exclusive; private int streamId; @@ -35,13 +34,10 @@ public class PriorityBodyParser extends BodyParser super(headerParser, listener); } - @Override - protected void reset() + private void reset() { - super.reset(); state = State.EXCLUSIVE; cursor = 0; - exclusive = false; streamId = 0; } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java index d9fed1d3716..fe9171352f9 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java @@ -33,10 +33,8 @@ public class ResetBodyParser extends BodyParser super(headerParser, listener); } - @Override - protected void reset() + private void reset() { - super.reset(); state = State.ERROR; cursor = 0; error = 0; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java new file mode 100644 index 00000000000..18098ebb87c --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -0,0 +1,148 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jetty.http2.frames.SettingsFrame; + +public class SettingsBodyParser extends BodyParser +{ + private State state = State.PREPARE; + private int cursor; + private int length; + private int settingId; + private int settingValue; + private Map settings; + + public SettingsBodyParser(HeaderParser headerParser, Parser.Listener listener) + { + super(headerParser, listener); + } + + private void reset() + { + state = State.PREPARE; + cursor = 0; + length = 0; + settingId = 0; + settingValue = 0; + settings = null; + } + + @Override + protected boolean emptyBody() + { + return onSettings(new HashMap()) == Result.ASYNC; + } + + @Override + public Result parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case PREPARE: + { + length = getBodyLength(); + settings = new HashMap<>(); + state = State.SETTING_ID; + if (length == 0) + { + return onSettings(settings); + } + break; + } + case SETTING_ID: + { + settingId = buffer.get() & 0xFF; + state = State.SETTING_VALUE; + --length; + if (length == 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings"); + } + break; + } + case SETTING_VALUE: + { + if (buffer.remaining() >= 4) + { + settingValue = buffer.getInt(); + settings.put(settingId, settingValue); + state = State.SETTING_ID; + length -= 4; + if (length == 0) + { + return onSettings(settings); + } + } + else + { + cursor = 4; + settingValue = 0; + state = State.SETTING_VALUE_BYTES; + } + break; + } + case SETTING_VALUE_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + settingValue += currByte << (8 * cursor); + --length; + if (cursor > 0 && length == 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings"); + } + if (cursor == 0) + { + settings.put(settingId, settingValue); + state = State.SETTING_ID; + if (length == 0) + { + return onSettings(settings); + } + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return Result.PENDING; + } + + private Result onSettings(Map settings) + { + SettingsFrame frame = new SettingsFrame(settings, hasFlag(0x1)); + reset(); + return notifySettings(frame) ? Result.ASYNC : Result.COMPLETE; + } + + private enum State + { + PREPARE, SETTING_ID, SETTING_VALUE, SETTING_VALUE_BYTES + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java index b651c9d392a..0ed06b81428 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java @@ -33,10 +33,8 @@ public class WindowUpdateBodyParser extends BodyParser super(headerParser, listener); } - @Override - protected void reset() + private void reset() { - super.reset(); state = State.WINDOW_DELTA; cursor = 0; windowDelta = 0; diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 4670f3fffe7..de879438987 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; import org.junit.Assert; import org.junit.Test; @@ -43,6 +44,18 @@ public class DataGenerateParseTest random.nextBytes(largeContent); } + @Test + public void testGenerateParseNoContentNoPadding() + { + ByteBuffer content = BufferUtil.EMPTY_BUFFER; + List frames = testGenerateParse(0, content); + Assert.assertEquals(1, frames.size()); + DataFrame frame = frames.get(0); + Assert.assertTrue(frame.getStreamId() != 0); + Assert.assertTrue(frame.isEnd()); + Assert.assertEquals(content, frame.getData()); + } + @Test public void testGenerateParseSmallContentNoPadding() { diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java new file mode 100644 index 00000000000..f52f383b3e9 --- /dev/null +++ b/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -0,0 +1,171 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.ErrorCode; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Test; + +public class SettingsGenerateParseTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + @Test + public void testGenerateParseNoSettings() throws Exception + { + List frames = testGenerateParse(Collections.emptyMap()); + Assert.assertEquals(1, frames.size()); + SettingsFrame frame = frames.get(0); + Assert.assertEquals(0, frame.getSettings().size()); + Assert.assertTrue(frame.isReply()); + } + + @Test + public void testGenerateParseSettings() throws Exception + { + Map settings1 = new HashMap<>(); + int key1 = 13; + Integer value1 = 17; + settings1.put(key1, value1); + int key2 = 19; + Integer value2 = 23; + settings1.put(key2, value2); + List frames = testGenerateParse(settings1); + Assert.assertEquals(1, frames.size()); + SettingsFrame frame = frames.get(0); + Map settings2 = frame.getSettings(); + Assert.assertEquals(2, settings2.size()); + Assert.assertEquals(value1, settings2.get(key1)); + Assert.assertEquals(value2, settings2.get(key2)); + } + + private List testGenerateParse(Map settings) + { + Generator generator = new Generator(byteBufferPool); + + // Iterate a few times to be sure generator and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + Generator.Result result = generator.generateSettings(settings, true); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onSettings(SettingsFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + } + + return frames; + } + + @Test + public void testGenerateParseInvalidSettings() throws Exception + { + Generator generator = new Generator(byteBufferPool); + Map settings1 = new HashMap<>(); + settings1.put(13, 17); + Generator.Result result = generator.generateSettings(settings1, true); + // Modify the length of the frame to make it invalid + ByteBuffer bytes = result.getByteBuffers().get(0); + bytes.putShort(0, (short)(bytes.getShort(0) - 1)); + + final AtomicInteger errorRef = new AtomicInteger(); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public void onConnectionFailure(int error, String reason) + { + errorRef.set(error); + } + }); + + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(ErrorCode.PROTOCOL_ERROR, errorRef.get()); + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + Generator generator = new Generator(byteBufferPool); + + Map settings1 = new HashMap<>(); + int key = 13; + Integer value = 17; + settings1.put(key, value); + + final List frames = new ArrayList<>(); + Generator.Result result = generator.generateSettings(settings1, true); + Parser parser = new Parser(new Parser.Listener.Adapter() + { + @Override + public boolean onSettings(SettingsFrame frame) + { + frames.add(frame); + return false; + } + }); + + for (ByteBuffer buffer : result.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(1, frames.size()); + SettingsFrame frame = frames.get(0); + Map settings2 = frame.getSettings(); + Assert.assertEquals(1, settings2.size()); + Assert.assertEquals(value, settings2.get(key)); + Assert.assertTrue(frame.isReply()); + } +} From 6481bb926d7b6f258905a42046e1901a4715ec8d Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 6 Jun 2014 12:09:11 +0200 Subject: [PATCH 019/269] Strengthened frame body length checks. --- .../jetty/http2/parser/DataBodyParser.java | 13 +++++ .../jetty/http2/parser/GoAwayBodyParser.java | 51 +++++++++++++++---- .../jetty/http2/parser/PingBodyParser.java | 16 ++++-- .../http2/parser/PriorityBodyParser.java | 16 ++++-- .../jetty/http2/parser/ResetBodyParser.java | 16 ++++-- .../http2/parser/SettingsBodyParser.java | 12 ++--- .../http2/parser/WindowUpdateBodyParser.java | 16 ++++-- .../http2/frames/DataGenerateParseTest.java | 26 +++++++--- .../http2/frames/GoAwayGenerateParseTest.java | 0 .../http2/frames/PingGenerateParseTest.java | 0 .../frames/PriorityGenerateParseTest.java | 0 .../http2/frames/ResetGenerateParseTest.java | 0 .../frames/SettingsGenerateParseTest.java | 0 .../frames/WindowUpdateGenerateParseTest.java | 0 14 files changed, 127 insertions(+), 39 deletions(-) rename jetty-http2/src/test/{main => java}/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java (91%) rename jetty-http2/src/test/{main => java}/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java (100%) rename jetty-http2/src/test/{main => java}/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java (100%) rename jetty-http2/src/test/{main => java}/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java (100%) rename jetty-http2/src/test/{main => java}/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java (100%) rename jetty-http2/src/test/{main => java}/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java (100%) rename jetty-http2/src/test/{main => java}/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java (100%) diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index f230d651d09..41c2f9a6328 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -44,6 +44,11 @@ public class DataBodyParser extends BodyParser @Override protected boolean emptyBody() { + if (isPaddingHigh() || isPaddingLow()) + { + notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame"); + return false; + } return onData(BufferUtil.EMPTY_BUFFER, false); } @@ -75,6 +80,10 @@ public class DataBodyParser extends BodyParser { paddingLength = (buffer.get() & 0xFF) << 8; length -= 1; + if (length < 1 + 256) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame_padding"); + } state = State.PADDING_LOW; break; } @@ -82,6 +91,10 @@ public class DataBodyParser extends BodyParser { paddingLength += buffer.get() & 0xFF; length -= 1; + if (length < paddingLength) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame_padding"); + } length -= paddingLength; state = State.DATA; break; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java index 45671bc6969..9b01f517f6a 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java @@ -24,8 +24,9 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; public class GoAwayBodyParser extends BodyParser { - private State state = State.LAST_STREAM_ID; + private State state = State.PREPARE; private int cursor; + private int length; private int lastStreamId; private int error; private byte[] payload; @@ -37,8 +38,9 @@ public class GoAwayBodyParser extends BodyParser private void reset() { - state = State.LAST_STREAM_ID; + state = State.PREPARE; cursor = 0; + length = 0; lastStreamId = 0; error = 0; payload = null; @@ -51,6 +53,12 @@ public class GoAwayBodyParser extends BodyParser { switch (state) { + case PREPARE: + { + state = State.LAST_STREAM_ID; + length = getBodyLength(); + break; + } case LAST_STREAM_ID: { if (buffer.remaining() >= 4) @@ -58,6 +66,11 @@ public class GoAwayBodyParser extends BodyParser lastStreamId = buffer.getInt(); lastStreamId &= 0x7F_FF_FF_FF; state = State.ERROR; + length -= 4; + if (length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + } } else { @@ -71,10 +84,19 @@ public class GoAwayBodyParser extends BodyParser int currByte = buffer.get() & 0xFF; --cursor; lastStreamId += currByte << (8 * cursor); + --length; + if (cursor > 0 && length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + } if (cursor == 0) { lastStreamId &= 0x7F_FF_FF_FF; state = State.ERROR; + if (length == 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + } } break; } @@ -84,8 +106,12 @@ public class GoAwayBodyParser extends BodyParser { error = buffer.getInt(); state = State.PAYLOAD; - int payloadLength = getBodyLength() - 4 - 4; - if (payloadLength == 0) + length -= 4; + if (length < 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + } + if (length == 0) { return onGoAway(lastStreamId, error, null); } @@ -102,11 +128,15 @@ public class GoAwayBodyParser extends BodyParser int currByte = buffer.get() & 0xFF; --cursor; error += currByte << (8 * cursor); + --length; + if (cursor > 0 && length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + } if (cursor == 0) { state = State.PAYLOAD; - int payloadLength = getBodyLength() - 4 - 4; - if (payloadLength == 0) + if (length == 0) { return onGoAway(lastStreamId, error, null); } @@ -115,9 +145,8 @@ public class GoAwayBodyParser extends BodyParser } case PAYLOAD: { - int payloadLength = getBodyLength() - 4 - 4; - payload = new byte[payloadLength]; - if (buffer.remaining() >= payloadLength) + payload = new byte[length]; + if (buffer.remaining() >= length) { buffer.get(payload); return onGoAway(lastStreamId, error, payload); @@ -125,7 +154,7 @@ public class GoAwayBodyParser extends BodyParser else { state = State.PAYLOAD_BYTES; - cursor = payloadLength; + cursor = length; } break; } @@ -157,6 +186,6 @@ public class GoAwayBodyParser extends BodyParser private enum State { - LAST_STREAM_ID, LAST_STREAM_ID_BYTES, ERROR, ERROR_BYTES, PAYLOAD, PAYLOAD_BYTES + PREPARE, LAST_STREAM_ID, LAST_STREAM_ID_BYTES, ERROR, ERROR_BYTES, PAYLOAD, PAYLOAD_BYTES } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 173a5ea57b0..108f98314b0 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.http2.frames.PingFrame; public class PingBodyParser extends BodyParser { - private State state = State.PAYLOAD; + private State state = State.PREPARE; private int cursor; private byte[] payload; @@ -35,7 +35,7 @@ public class PingBodyParser extends BodyParser private void reset() { - state = State.PAYLOAD; + state = State.PREPARE; cursor = 0; payload = null; } @@ -47,6 +47,16 @@ public class PingBodyParser extends BodyParser { switch (state) { + case PREPARE: + { + int length = getBodyLength(); + if (length != 8) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_ping_frame"); + } + state = State.PAYLOAD; + break; + } case PAYLOAD: { payload = new byte[8]; @@ -90,6 +100,6 @@ public class PingBodyParser extends BodyParser private enum State { - PAYLOAD, PAYLOAD_BYTES + PREPARE, PAYLOAD, PAYLOAD_BYTES } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index e37785e0739..b845266273a 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.http2.frames.PriorityFrame; public class PriorityBodyParser extends BodyParser { - private State state = State.EXCLUSIVE; + private State state = State.PREPARE; private int cursor; private boolean exclusive; private int streamId; @@ -36,7 +36,7 @@ public class PriorityBodyParser extends BodyParser private void reset() { - state = State.EXCLUSIVE; + state = State.PREPARE; cursor = 0; exclusive = false; streamId = 0; @@ -49,6 +49,16 @@ public class PriorityBodyParser extends BodyParser { switch (state) { + case PREPARE: + { + int length = getBodyLength(); + if (length != 5) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_priority_frame"); + } + state = State.EXCLUSIVE; + break; + } case EXCLUSIVE: { // We must only peek the first byte and not advance the buffer @@ -108,6 +118,6 @@ public class PriorityBodyParser extends BodyParser private enum State { - EXCLUSIVE, STREAM_ID, STREAM_ID_BYTES, WEIGHT + PREPARE, EXCLUSIVE, STREAM_ID, STREAM_ID_BYTES, WEIGHT } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java index fe9171352f9..f74456eb384 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.http2.frames.ResetFrame; public class ResetBodyParser extends BodyParser { - private State state = State.ERROR; + private State state = State.PREPARE; private int cursor; private int error; @@ -35,7 +35,7 @@ public class ResetBodyParser extends BodyParser private void reset() { - state = State.ERROR; + state = State.PREPARE; cursor = 0; error = 0; } @@ -47,6 +47,16 @@ public class ResetBodyParser extends BodyParser { switch (state) { + case PREPARE: + { + int length = getBodyLength(); + if (length != 4) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_rst_stream_frame"); + } + state = State.ERROR; + break; + } case ERROR: { if (buffer.remaining() >= 4) @@ -89,6 +99,6 @@ public class ResetBodyParser extends BodyParser private enum State { - ERROR, ERROR_BYTES + PREPARE, ERROR, ERROR_BYTES } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index 18098ebb87c..7f613960fe1 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -66,10 +66,6 @@ public class SettingsBodyParser extends BodyParser length = getBodyLength(); settings = new HashMap<>(); state = State.SETTING_ID; - if (length == 0) - { - return onSettings(settings); - } break; } case SETTING_ID: @@ -77,9 +73,9 @@ public class SettingsBodyParser extends BodyParser settingId = buffer.get() & 0xFF; state = State.SETTING_VALUE; --length; - if (length == 0) + if (length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings"); + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); } break; } @@ -110,9 +106,9 @@ public class SettingsBodyParser extends BodyParser --cursor; settingValue += currByte << (8 * cursor); --length; - if (cursor > 0 && length == 0) + if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings"); + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); } if (cursor == 0) { diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java index 0ed06b81428..c64486c8057 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame; public class WindowUpdateBodyParser extends BodyParser { - private State state = State.WINDOW_DELTA; + private State state = State.PREPARE; private int cursor; private int windowDelta; @@ -35,7 +35,7 @@ public class WindowUpdateBodyParser extends BodyParser private void reset() { - state = State.WINDOW_DELTA; + state = State.PREPARE; cursor = 0; windowDelta = 0; } @@ -47,6 +47,16 @@ public class WindowUpdateBodyParser extends BodyParser { switch (state) { + case PREPARE: + { + int length = getBodyLength(); + if (length != 4) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_window_update_frame"); + } + state = State.WINDOW_DELTA; + break; + } case WINDOW_DELTA: { if (buffer.remaining() >= 4) @@ -91,6 +101,6 @@ public class WindowUpdateBodyParser extends BodyParser private enum State { - WINDOW_DELTA, WINDOW_DELTA_BYTES + PREPARE, WINDOW_DELTA, WINDOW_DELTA_BYTES } } diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java similarity index 91% rename from jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java rename to jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index de879438987..841553fe004 100644 --- a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -47,13 +47,19 @@ public class DataGenerateParseTest @Test public void testGenerateParseNoContentNoPadding() { - ByteBuffer content = BufferUtil.EMPTY_BUFFER; - List frames = testGenerateParse(0, content); - Assert.assertEquals(1, frames.size()); - DataFrame frame = frames.get(0); - Assert.assertTrue(frame.getStreamId() != 0); - Assert.assertTrue(frame.isEnd()); - Assert.assertEquals(content, frame.getData()); + testGenerateParseContent(0, BufferUtil.EMPTY_BUFFER); + } + + @Test + public void testGenerateParseNoContentSmallPadding() + { + testGenerateParseContent(128, BufferUtil.EMPTY_BUFFER); + } + + @Test + public void testGenerateParseNoContentLargePadding() + { + testGenerateParseContent(1024, BufferUtil.EMPTY_BUFFER); } @Test @@ -76,7 +82,11 @@ public class DataGenerateParseTest private void testGenerateParseSmallContent(int paddingLength) { - ByteBuffer content = ByteBuffer.wrap(smallContent); + testGenerateParseContent(paddingLength, ByteBuffer.wrap(smallContent)); + } + + private void testGenerateParseContent(int paddingLength, ByteBuffer content) + { List frames = testGenerateParse(paddingLength, content); Assert.assertEquals(1, frames.size()); DataFrame frame = frames.get(0); diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java similarity index 100% rename from jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java rename to jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java similarity index 100% rename from jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java rename to jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java similarity index 100% rename from jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java rename to jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java similarity index 100% rename from jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java rename to jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java similarity index 100% rename from jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java rename to jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java diff --git a/jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java similarity index 100% rename from jetty-http2/src/test/main/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java rename to jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java From 9c13b300f0454f8cd448cba659f24d6181e88857 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 6 Jun 2014 12:30:39 +0200 Subject: [PATCH 020/269] Improved signature for generating DATA frames, with explicit padding bytes. --- .../jetty/http2/generator/Generator.java | 36 +++++++++---------- .../http2/frames/DataGenerateParseTest.java | 4 +-- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index daedce95c2e..868ebec77cd 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -37,15 +37,16 @@ public class Generator this.byteBufferPool = byteBufferPool; } - public Result generateData(int streamId, int paddingLength, ByteBuffer data, boolean last, boolean compress) + public Result generateData(int streamId, ByteBuffer data, boolean last, boolean compress, byte[] paddingBytes) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); + int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; // Leave space for at least one byte of content. if (paddingLength > DataFrame.MAX_LENGTH - 3) throw new IllegalArgumentException("Invalid padding length: " + paddingLength); - int paddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; + int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; // TODO: here we should compress the data, and then reason on the data length ! @@ -54,13 +55,13 @@ public class Generator Result result = new Result(byteBufferPool); // Can we fit just one frame ? - if (dataLength + paddingBytes + paddingLength <= DataFrame.MAX_LENGTH) + if (dataLength + extraPaddingBytes + paddingLength <= DataFrame.MAX_LENGTH) { - generateData(result, streamId, paddingBytes, paddingLength, data, last, compress); + generateData(result, streamId, data, last, compress, extraPaddingBytes, paddingBytes); } else { - int dataBytesPerFrame = DataFrame.MAX_LENGTH - paddingBytes - paddingLength; + int dataBytesPerFrame = DataFrame.MAX_LENGTH - extraPaddingBytes - paddingLength; int frames = dataLength / dataBytesPerFrame; if (frames * dataBytesPerFrame != dataLength) { @@ -72,7 +73,7 @@ public class Generator data.limit(Math.min(dataBytesPerFrame * i, limit)); ByteBuffer slice = data.slice(); data.position(data.limit()); - generateData(result, streamId, paddingBytes, paddingLength, slice, i == frames && last, compress); + generateData(result, streamId, slice, i == frames && last, compress, extraPaddingBytes, paddingBytes); } } return result; @@ -197,25 +198,26 @@ public class Generator return result; } - private void generateData(Result result, int streamId, int paddingBytes, int paddingLength, ByteBuffer data, boolean last, boolean compress) + private void generateData(Result result, int streamId, ByteBuffer data, boolean last, boolean compress, int extraPaddingBytes, byte[] paddingBytes) { - int length = paddingBytes + data.remaining() + paddingLength; + int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; + int length = extraPaddingBytes + data.remaining() + paddingLength; int flags = 0; if (last) flags |= 0x01; - if (paddingBytes > 0) + if (extraPaddingBytes > 0) flags |= 0x08; - if (paddingBytes > 1) + if (extraPaddingBytes > 1) flags |= 0x10; if (compress) flags |= 0x20; - ByteBuffer header = generateHeader(FrameType.DATA, 8 + paddingBytes, length, flags, streamId); + ByteBuffer header = generateHeader(FrameType.DATA, 8 + extraPaddingBytes, length, flags, streamId); - if (paddingBytes == 2) + if (extraPaddingBytes == 2) header.putShort((short)paddingLength); - else if (paddingBytes == 1) + else if (extraPaddingBytes == 1) header.put((byte)paddingLength); BufferUtil.flipToFlush(header, 0); @@ -223,13 +225,9 @@ public class Generator result.add(data, false); - if (paddingBytes > 0) + if (paddingBytes != null) { - ByteBuffer padding = byteBufferPool.acquire(paddingLength, true); - BufferUtil.clearToFill(padding); - padding.position(paddingLength); - BufferUtil.flipToFlush(padding, 0); - result.add(padding, true); + result.add(ByteBuffer.wrap(paddingBytes), false); } } diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 841553fe004..8f0b2ce1730 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -141,7 +141,7 @@ public class DataGenerateParseTest Generator.Result result = new Generator.Result(byteBufferPool); for (int j = 1; j <= data.length; ++j) { - result = result.merge(generator.generateData(13, paddingLength, data[j - 1].slice(), j == data.length, false)); + result = result.merge(generator.generateData(13, data[j - 1].slice(), j == data.length, false, new byte[paddingLength])); } Parser parser = new Parser(new Parser.Listener.Adapter() @@ -169,7 +169,7 @@ public class DataGenerateParseTest { Generator generator = new Generator(byteBufferPool); - Generator.Result result = generator.generateData(13, 1024, ByteBuffer.wrap(largeContent).slice(), true, false); + Generator.Result result = generator.generateData(13, ByteBuffer.wrap(largeContent).slice(), true, false, new byte[1024]); final List frames = new ArrayList<>(); Parser parser = new Parser(new Parser.Listener.Adapter() From 244158ee3e5571da831b1fbca5cbd6676ef85389 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 6 Jun 2014 16:22:42 +0200 Subject: [PATCH 021/269] Introduced class ByteBufferPool.Lease to keep track of buffers with associated information of whether they have been borrowed from the ByteBufferPool or not. --- .../jetty/fcgi/generator/Generator.java | 1 + .../org/eclipse/jetty/hpack/HpackEncoder.java | 18 +++---- .../org/eclipse/jetty/io/ByteBufferPool.java | 53 +++++++++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java index 1fbf3d85ff4..04e6c0aa70b 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java @@ -80,6 +80,7 @@ public class Generator return result; } + // TODO: rewrite this class in light of ByteBufferPool.Lease. public static class Result implements Callback { private final List callbacks = new ArrayList<>(2); diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java index e8a75171388..34edb32281e 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java @@ -19,26 +19,20 @@ package org.eclipse.jetty.hpack; -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.List; - import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.io.ByteBufferPool; - -/* ------------------------------------------------------------ */ -/** - */ public class HpackEncoder { - public HpackEncoder(ByteBufferPool pool) + private final ByteBufferPool byteBufferPool; + + public HpackEncoder(ByteBufferPool byteBufferPool) { - + this.byteBufferPool = byteBufferPool; } - public List encode(HttpFields fields) + public ByteBufferPool.Lease encode(HttpFields fields) { - return Collections.emptyList(); + return new ByteBufferPool.Lease(byteBufferPool); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index 302adde35d8..f0153dc2f7a 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -19,6 +19,8 @@ package org.eclipse.jetty.io; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; /** *

A {@link ByteBuffer} pool.

@@ -48,4 +50,55 @@ public interface ByteBufferPool * @see #acquire(int, boolean) */ public void release(ByteBuffer buffer); + + public static class Lease + { + private final ByteBufferPool byteBufferPool; + private final List buffers; + private final List recycles; + + public Lease(ByteBufferPool byteBufferPool) + { + this.byteBufferPool = byteBufferPool; + this.buffers = new ArrayList<>(); + this.recycles = new ArrayList<>(); + } + + public void add(ByteBuffer buffer, boolean recycle) + { + buffers.add(buffer); + recycles.add(recycle); + } + + public List getByteBuffers() + { + return buffers; + } + + public Lease merge(Lease that) + { + assert byteBufferPool == that.byteBufferPool; + buffers.addAll(that.buffers); + recycles.addAll(that.recycles); + return this; + } + + public long getTotalLength() + { + long length = 0; + for (int i = 0; i < buffers.size(); ++i) + length += buffers.get(i).remaining(); + return length; + } + + public void recycle() + { + for (int i = 0; i < buffers.size(); ++i) + { + ByteBuffer buffer = buffers.get(i); + if (recycles.get(i)) + byteBufferPool.release(buffer); + } + } + } } From 1da95c974db3f57b8b2ec6756bb81ed2e1e7077a Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 6 Jun 2014 16:32:31 +0200 Subject: [PATCH 022/269] Implemented parser and generator for HEADERS frame. --- jetty-http2/pom.xml | 10 + .../eclipse/jetty/http2/frames/DataFrame.java | 20 +- .../org/eclipse/jetty/http2/frames/Flag.java | 31 +++ .../org/eclipse/jetty/http2/frames/Frame.java | 25 ++ .../jetty/http2/frames/HeadersFrame.java | 37 +++ .../jetty/http2/generator/Generator.java | 175 +++++++------- .../jetty/http2/parser/BodyParser.java | 21 +- .../jetty/http2/parser/HeaderParser.java | 4 +- .../jetty/http2/parser/HeadersBodyParser.java | 216 ++++++++++++++++++ .../eclipse/jetty/http2/parser/Parser.java | 14 ++ .../jetty/http2/parser/PingBodyParser.java | 3 +- .../http2/parser/SettingsBodyParser.java | 3 +- .../http2/frames/DataGenerateParseTest.java | 14 +- .../http2/frames/GoAwayGenerateParseTest.java | 8 +- .../frames/HeadersGenerateParseTest.java | 34 +++ .../http2/frames/PingGenerateParseTest.java | 8 +- .../frames/PriorityGenerateParseTest.java | 8 +- .../http2/frames/ResetGenerateParseTest.java | 8 +- .../frames/SettingsGenerateParseTest.java | 14 +- .../frames/WindowUpdateGenerateParseTest.java | 8 +- 20 files changed, 531 insertions(+), 130 deletions(-) create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Flag.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Frame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java create mode 100644 jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java create mode 100644 jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index f1178b35ded..9c5d3da7bbe 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -13,6 +13,16 @@ ${project.groupId}.http + + org.eclipse.jetty + jetty-http + ${project.version} + + + org.eclipse.jetty + jetty-hpack + ${project.version} + org.eclipse.jetty jetty-io diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java index 84128a89ef1..9badd6fe9eb 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -20,19 +20,17 @@ package org.eclipse.jetty.http2.frames; import java.nio.ByteBuffer; -public class DataFrame +public class DataFrame extends Frame { - public static final int MAX_LENGTH = 0x3F_FF; - private final int streamId; private final ByteBuffer data; - private boolean end; + private boolean endStream; - public DataFrame(int streamId, ByteBuffer data, boolean end) + public DataFrame(int streamId, ByteBuffer data, boolean endStream) { this.streamId = streamId; this.data = data; - this.end = end; + this.endStream = endStream; } public int getStreamId() @@ -40,13 +38,13 @@ public class DataFrame return streamId; } - public boolean isEnd() - { - return end; - } - public ByteBuffer getData() { return data; } + + public boolean isEndStream() + { + return endStream; + } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Flag.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Flag.java new file mode 100644 index 00000000000..f29256241c6 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Flag.java @@ -0,0 +1,31 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public interface Flag +{ + public static final int END_STREAM = 0x01; + public static final int ACK = END_STREAM; + public static final int END_SEGMENT = 0x02; + public static final int END_HEADERS = 0x04; + public static final int PADDING_LOW = 0x08; + public static final int PADDING_HIGH = 0x10; + public static final int COMPRESS = 0x20; + public static final int PRIORITY = COMPRESS; +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Frame.java new file mode 100644 index 00000000000..0d3bf269ab5 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Frame.java @@ -0,0 +1,25 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public abstract class Frame +{ + public static final int HEADER_LENGTH = 8; + public static final int MAX_LENGTH = 0x3F_FF; +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java new file mode 100644 index 00000000000..01df9ab37ac --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java @@ -0,0 +1,37 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import org.eclipse.jetty.http.HttpFields; + +public class HeadersFrame +{ + private final int streamId; + private final HttpFields fields; + private final PriorityFrame priority; + private final boolean endStream; + + public HeadersFrame(int streamId, HttpFields fields, PriorityFrame priority, boolean endStream) + { + this.streamId = streamId; + this.fields = fields; + this.priority = priority; + this.endStream = endStream; + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 868ebec77cd..6fefe05c0f2 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -19,11 +19,12 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; import java.util.Map; -import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.hpack.HpackEncoder; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; @@ -31,19 +32,21 @@ import org.eclipse.jetty.util.BufferUtil; public class Generator { private final ByteBufferPool byteBufferPool; + private final HpackEncoder encoder; public Generator(ByteBufferPool byteBufferPool) { this.byteBufferPool = byteBufferPool; + this.encoder = new HpackEncoder(byteBufferPool); } - public Result generateData(int streamId, ByteBuffer data, boolean last, boolean compress, byte[] paddingBytes) + public ByteBufferPool.Lease generateData(int streamId, ByteBuffer data, boolean last, boolean compress, byte[] paddingBytes) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; // Leave space for at least one byte of content. - if (paddingLength > DataFrame.MAX_LENGTH - 3) + if (paddingLength > Frame.MAX_LENGTH - 3) throw new IllegalArgumentException("Invalid padding length: " + paddingLength); int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; @@ -52,16 +55,16 @@ public class Generator int dataLength = data.remaining(); - Result result = new Result(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); // Can we fit just one frame ? - if (dataLength + extraPaddingBytes + paddingLength <= DataFrame.MAX_LENGTH) + if (dataLength + extraPaddingBytes + paddingLength <= Frame.MAX_LENGTH) { - generateData(result, streamId, data, last, compress, extraPaddingBytes, paddingBytes); + generateData(lease, streamId, data, last, compress, extraPaddingBytes, paddingBytes); } else { - int dataBytesPerFrame = DataFrame.MAX_LENGTH - extraPaddingBytes - paddingLength; + int dataBytesPerFrame = Frame.MAX_LENGTH - extraPaddingBytes - paddingLength; int frames = dataLength / dataBytesPerFrame; if (frames * dataBytesPerFrame != dataLength) { @@ -73,20 +76,69 @@ public class Generator data.limit(Math.min(dataBytesPerFrame * i, limit)); ByteBuffer slice = data.slice(); data.position(data.limit()); - generateData(result, streamId, slice, i == frames && last, compress, extraPaddingBytes, paddingBytes); + generateData(lease, streamId, slice, i == frames && last, compress, extraPaddingBytes, paddingBytes); } } - return result; + return lease; } - public Result generatePriority(int streamId, int dependentStreamId, int weight, boolean exclusive) + public ByteBufferPool.Lease generateHeaders(int streamId, HttpFields headers, boolean contentFollows, byte[] paddingBytes) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; + // Leave space for at least one byte of content. + if (paddingLength > Frame.MAX_LENGTH - 3) + throw new IllegalArgumentException("Invalid padding length: " + paddingLength); + + int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; + + ByteBufferPool.Lease hpackBuffers = encoder.encode(headers); + + long hpackLength = hpackBuffers.getTotalLength(); + + long length = extraPaddingBytes + hpackLength + paddingLength; + if (length > Frame.MAX_LENGTH) + throw new IllegalArgumentException("Invalid headers, too big"); + + int flags = Flag.END_HEADERS; + if (!contentFollows) + flags |= Flag.END_STREAM; + if (extraPaddingBytes > 0) + flags |= Flag.PADDING_LOW; + if (extraPaddingBytes > 1) + flags |= Flag.PADDING_HIGH; + + ByteBuffer header = generateHeader(FrameType.HEADERS, Frame.HEADER_LENGTH + extraPaddingBytes, (int)length, flags, streamId); + + if (extraPaddingBytes == 2) + header.putShort((short)paddingLength); + else if (extraPaddingBytes == 1) + header.put((byte)paddingLength); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + + BufferUtil.flipToFlush(header, 0); + lease.add(header, true); + + lease.merge(hpackBuffers); + + if (paddingBytes != null) + { + lease.add(ByteBuffer.wrap(paddingBytes), false); + } + + return lease; + } + + public ByteBufferPool.Lease generatePriority(int streamId, int dependentStreamId, int weight, boolean exclusive) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); if (dependentStreamId < 0) throw new IllegalArgumentException("Invalid dependent stream id: " + dependentStreamId); - Result result = new Result(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); ByteBuffer header = generateHeader(FrameType.PRIORITY, 5, 0, dependentStreamId); @@ -98,31 +150,31 @@ public class Generator header.put((byte)weight); BufferUtil.flipToFlush(header, 0); - result.add(header, true); + lease.add(header, true); - return result; + return lease; } - public Result generateReset(int streamId, int error) + public ByteBufferPool.Lease generateReset(int streamId, int error) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); - Result result = new Result(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); ByteBuffer header = generateHeader(FrameType.RST_STREAM, 4, 0, streamId); header.putInt(error); BufferUtil.flipToFlush(header, 0); - result.add(header, true); + lease.add(header, true); - return result; + return lease; } - public Result generateSettings(Map settings, boolean reply) + public ByteBufferPool.Lease generateSettings(Map settings, boolean reply) { - Result result = new Result(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); ByteBuffer header = generateHeader(FrameType.SETTINGS, 5 * settings.size(), reply ? 0x01 : 0x00, 0); @@ -133,34 +185,34 @@ public class Generator } BufferUtil.flipToFlush(header, 0); - result.add(header, true); + lease.add(header, true); - return result; + return lease; } - public Result generatePing(byte[] payload, boolean reply) + public ByteBufferPool.Lease generatePing(byte[] payload, boolean reply) { if (payload.length != 8) throw new IllegalArgumentException("Invalid payload length: " + payload.length); - Result result = new Result(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); ByteBuffer header = generateHeader(FrameType.PING, 8, reply ? 0x01 : 0x00, 0); header.put(payload); BufferUtil.flipToFlush(header, 0); - result.add(header, true); + lease.add(header, true); - return result; + return lease; } - public Result generateGoAway(int lastStreamId, int error, byte[] payload) + public ByteBufferPool.Lease generateGoAway(int lastStreamId, int error, byte[] payload) { if (lastStreamId < 0) throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId); - Result result = new Result(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); int length = 4 + 4 + (payload != null ? payload.length : 0); ByteBuffer header = generateHeader(FrameType.GO_AWAY, length, 0, 0); @@ -174,46 +226,46 @@ public class Generator } BufferUtil.flipToFlush(header, 0); - result.add(header, true); + lease.add(header, true); - return result; + return lease; } - public Result generateWindowUpdate(int streamId, int windowUpdate) + public ByteBufferPool.Lease generateWindowUpdate(int streamId, int windowUpdate) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); if (windowUpdate < 0) throw new IllegalArgumentException("Invalid window update: " + windowUpdate); - Result result = new Result(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); ByteBuffer header = generateHeader(FrameType.WINDOW_UPDATE, 4, 0, streamId); header.putInt(windowUpdate); BufferUtil.flipToFlush(header, 0); - result.add(header, true); + lease.add(header, true); - return result; + return lease; } - private void generateData(Result result, int streamId, ByteBuffer data, boolean last, boolean compress, int extraPaddingBytes, byte[] paddingBytes) + private void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, boolean compress, int extraPaddingBytes, byte[] paddingBytes) { int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; int length = extraPaddingBytes + data.remaining() + paddingLength; int flags = 0; if (last) - flags |= 0x01; + flags |= Flag.END_STREAM; if (extraPaddingBytes > 0) - flags |= 0x08; + flags |= Flag.PADDING_LOW; if (extraPaddingBytes > 1) - flags |= 0x10; + flags |= Flag.PADDING_HIGH; if (compress) - flags |= 0x20; + flags |= Flag.COMPRESS; - ByteBuffer header = generateHeader(FrameType.DATA, 8 + extraPaddingBytes, length, flags, streamId); + ByteBuffer header = generateHeader(FrameType.DATA, Frame.HEADER_LENGTH + extraPaddingBytes, length, flags, streamId); if (extraPaddingBytes == 2) header.putShort((short)paddingLength); @@ -221,19 +273,19 @@ public class Generator header.put((byte)paddingLength); BufferUtil.flipToFlush(header, 0); - result.add(header, true); + lease.add(header, true); - result.add(data, false); + lease.add(data, false); if (paddingBytes != null) { - result.add(ByteBuffer.wrap(paddingBytes), false); + lease.add(ByteBuffer.wrap(paddingBytes), false); } } private ByteBuffer generateHeader(FrameType frameType, int length, int flags, int streamId) { - return generateHeader(frameType, 8 + length, length, flags, streamId); + return generateHeader(frameType, Frame.HEADER_LENGTH + length, length, flags, streamId); } private ByteBuffer generateHeader(FrameType frameType, int capacity, int length, int flags, int streamId) @@ -248,37 +300,4 @@ public class Generator return header; } - - public static class Result - { - private final ByteBufferPool byteBufferPool; - private final List buffers; - private final List recycles; - - public Result(ByteBufferPool byteBufferPool) - { - this.byteBufferPool = byteBufferPool; - this.buffers = new ArrayList<>(); - this.recycles = new ArrayList<>(); - } - - public void add(ByteBuffer buffer, boolean recycle) - { - buffers.add(buffer); - recycles.add(recycle); - } - - public List getByteBuffers() - { - return buffers; - } - - public Result merge(Result that) - { - assert byteBufferPool == that.byteBufferPool; - buffers.addAll(that.buffers); - recycles.addAll(that.recycles); - return this; - } - } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 1d9040c152f..51fcfda05b9 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -21,7 +21,9 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.GoAwayFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; @@ -58,17 +60,17 @@ public abstract class BodyParser protected boolean isPaddingHigh() { - return headerParser.hasFlag(0x10); + return headerParser.hasFlag(Flag.PADDING_HIGH); } protected boolean isPaddingLow() { - return headerParser.hasFlag(0x8); + return headerParser.hasFlag(Flag.PADDING_LOW); } protected boolean isEndStream() { - return headerParser.hasFlag(0x1); + return headerParser.hasFlag(Flag.END_STREAM); } protected int getStreamId() @@ -94,6 +96,19 @@ public abstract class BodyParser } } + protected boolean notifyHeaders(HeadersFrame frame) + { + try + { + return listener.onHeaders(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + protected boolean notifyPriority(PriorityFrame frame) { try diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java index fe72e1c2962..00088233665 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; -import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.Frame; public class HeaderParser { @@ -64,7 +64,7 @@ public class HeaderParser if (++cursor == 2) { // First 2 most significant bits MUST be ignored as per specification. - length &= DataFrame.MAX_LENGTH; + length &= Frame.MAX_LENGTH; state = State.TYPE; } break; diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java new file mode 100644 index 00000000000..0d92dd40bd3 --- /dev/null +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -0,0 +1,216 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PriorityFrame; + +public class HeadersBodyParser extends BodyParser +{ + private State state = State.PREPARE; + private int cursor; + private int length; + private int paddingLength; + private boolean exclusive; + private int streamId; + private int weight; + private HttpFields fields; + + public HeadersBodyParser(HeaderParser headerParser, Parser.Listener listener) + { + super(headerParser, listener); + } + + private void reset() + { + state = State.PREPARE; + cursor = 0; + length = 0; + paddingLength = 0; + exclusive = false; + streamId = 0; + weight = 0; + fields = null; + } + + @Override + public Result parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case PREPARE: + { + length = getBodyLength(); + fields = new HttpFields(); + if (isPaddingHigh()) + { + state = State.PADDING_HIGH; + } + else if (isPaddingLow()) + { + state = State.PADDING_LOW; + } + else if (hasFlag(Flag.PRIORITY)) + { + state = State.EXCLUSIVE; + } + else + { + state = State.HEADERS; + } + break; + } + case PADDING_HIGH: + { + paddingLength = (buffer.get() & 0xFF) << 8; + length -= 1; + if (length < 1 + 256) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame_padding"); + } + state = State.PADDING_LOW; + break; + } + case PADDING_LOW: + { + paddingLength += buffer.get() & 0xFF; + length -= 1; + if (length < paddingLength) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame_padding"); + } + length -= paddingLength; + state = hasFlag(Flag.PRIORITY) ? State.EXCLUSIVE : State.HEADERS; + break; + } + case EXCLUSIVE: + { + // We must only peek the first byte and not advance the buffer + // because the 31 least significant bits represent the stream id. + int currByte = buffer.get(buffer.position()); + exclusive = (currByte & 0x80) == 0x80; + state = State.STREAM_ID; + break; + } + case STREAM_ID: + { + if (buffer.remaining() >= 4) + { + streamId = buffer.getInt(); + streamId &= 0x7F_FF_FF_FF; + length -= 4; + state = State.WEIGHT; + if (length < 1) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + } + } + else + { + state = State.STREAM_ID_BYTES; + cursor = 4; + } + break; + } + case STREAM_ID_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + streamId += currByte << (8 * cursor); + --length; + if (cursor > 0 && length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + } + if (cursor == 0) + { + streamId &= 0x7F_FF_FF_FF; + state = State.WEIGHT; + if (length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + } + } + break; + } + case WEIGHT: + { + weight = buffer.get() & 0xFF; + --length; + state = State.HEADERS; + if (length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + } + break; + } + case HEADERS: + { + // TODO: use HpackDecoder + + state = State.PADDING; + if (onHeaders(streamId, weight, exclusive, fields)) + { + return Result.ASYNC; + } + break; + } + case PADDING: + { + int size = Math.min(buffer.remaining(), paddingLength); + buffer.position(buffer.position() + size); + paddingLength -= size; + if (paddingLength == 0) + { + reset(); + return Result.COMPLETE; + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return Result.PENDING; + } + + private boolean onHeaders(int streamId, int weight, boolean exclusive, HttpFields fields) + { + PriorityFrame priorityFrame = null; + if (hasFlag(Flag.PRIORITY)) + { + priorityFrame = new PriorityFrame(streamId, getStreamId(), weight, exclusive); + } + HeadersFrame frame = new HeadersFrame(getStreamId(), fields, priorityFrame, isEndStream()); + return notifyHeaders(frame); + } + + private enum State + { + PREPARE, PADDING_HIGH, PADDING_LOW, EXCLUSIVE, STREAM_ID, STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 01281c21bca..bca7252f306 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.GoAwayFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; @@ -44,12 +45,17 @@ public class Parser { this.listener = listener; bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener); + bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener); bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); bodyParsers[FrameType.SETTINGS.getType()] = new SettingsBodyParser(headerParser, listener); + bodyParsers[FrameType.PUSH_PROMISE.getType()] = null; // TODO bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener); bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener); bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener); + bodyParsers[FrameType.CONTINUATION.getType()] = null; // TODO + bodyParsers[FrameType.ALTSVC.getType()] = null; // TODO + bodyParsers[FrameType.BLOCKED.getType()] = null; // TODO } private void reset() @@ -142,6 +148,8 @@ public class Parser { public boolean onData(DataFrame frame); + public boolean onHeaders(HeadersFrame frame); + public boolean onPriority(PriorityFrame frame); public boolean onReset(ResetFrame frame); @@ -164,6 +172,12 @@ public class Parser return false; } + @Override + public boolean onHeaders(HeadersFrame frame) + { + return false; + } + @Override public boolean onPriority(PriorityFrame frame) { diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 108f98314b0..746d29deaaa 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.PingFrame; public class PingBodyParser extends BodyParser @@ -93,7 +94,7 @@ public class PingBodyParser extends BodyParser private Result onPing(byte[] payload) { - PingFrame frame = new PingFrame(payload, hasFlag(0x1)); + PingFrame frame = new PingFrame(payload, hasFlag(Flag.ACK)); reset(); return notifyPing(frame) ? Result.ASYNC : Result.COMPLETE; } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index 7f613960fe1..d1649fc4dbd 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.SettingsFrame; public class SettingsBodyParser extends BodyParser @@ -132,7 +133,7 @@ public class SettingsBodyParser extends BodyParser private Result onSettings(Map settings) { - SettingsFrame frame = new SettingsFrame(settings, hasFlag(0x1)); + SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flag.ACK)); reset(); return notifySettings(frame) ? Result.ASYNC : Result.COMPLETE; } diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 8f0b2ce1730..1d1256b5fea 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -91,7 +91,7 @@ public class DataGenerateParseTest Assert.assertEquals(1, frames.size()); DataFrame frame = frames.get(0); Assert.assertTrue(frame.getStreamId() != 0); - Assert.assertTrue(frame.isEnd()); + Assert.assertTrue(frame.isEndStream()); Assert.assertEquals(content, frame.getData()); } @@ -123,7 +123,7 @@ public class DataGenerateParseTest { DataFrame frame = frames.get(i - 1); Assert.assertTrue(frame.getStreamId() != 0); - Assert.assertEquals(i == frames.size(), frame.isEnd()); + Assert.assertEquals(i == frames.size(), frame.isEndStream()); aggregate.put(frame.getData()); } aggregate.flip(); @@ -138,10 +138,10 @@ public class DataGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - Generator.Result result = new Generator.Result(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); for (int j = 1; j <= data.length; ++j) { - result = result.merge(generator.generateData(13, data[j - 1].slice(), j == data.length, false, new byte[paddingLength])); + lease = lease.merge(generator.generateData(13, data[j - 1].slice(), j == data.length, false, new byte[paddingLength])); } Parser parser = new Parser(new Parser.Listener.Adapter() @@ -155,7 +155,7 @@ public class DataGenerateParseTest }); frames.clear(); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { parser.parse(buffer); } @@ -169,7 +169,7 @@ public class DataGenerateParseTest { Generator generator = new Generator(byteBufferPool); - Generator.Result result = generator.generateData(13, ByteBuffer.wrap(largeContent).slice(), true, false, new byte[1024]); + ByteBufferPool.Lease lease = generator.generateData(13, ByteBuffer.wrap(largeContent).slice(), true, false, new byte[1024]); final List frames = new ArrayList<>(); Parser parser = new Parser(new Parser.Listener.Adapter() @@ -182,7 +182,7 @@ public class DataGenerateParseTest } }); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java index dfc363d1ed6..21f7ad9e8d7 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java @@ -46,7 +46,7 @@ public class GoAwayGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - Generator.Result result = generator.generateGoAway(lastStreamId, error, null); + ByteBufferPool.Lease lease = generator.generateGoAway(lastStreamId, error, null); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -58,7 +58,7 @@ public class GoAwayGenerateParseTest }); frames.clear(); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { @@ -85,7 +85,7 @@ public class GoAwayGenerateParseTest new Random().nextBytes(payload); final List frames = new ArrayList<>(); - Generator.Result result = generator.generateGoAway(lastStreamId, error, payload); + ByteBufferPool.Lease lease = generator.generateGoAway(lastStreamId, error, payload); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -96,7 +96,7 @@ public class GoAwayGenerateParseTest } }); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java new file mode 100644 index 00000000000..0ec83ca16ec --- /dev/null +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -0,0 +1,34 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Test; + +public class HeadersGenerateParseTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + @Test + public void testGenerateParse() throws Exception + { + // TODO + } +} diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java index 63f2b0adf21..a5b8e27bbc8 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -46,7 +46,7 @@ public class PingGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - Generator.Result result = generator.generatePing(payload, true); + ByteBufferPool.Lease lease = generator.generatePing(payload, true); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -58,7 +58,7 @@ public class PingGenerateParseTest }); frames.clear(); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { @@ -82,7 +82,7 @@ public class PingGenerateParseTest new Random().nextBytes(payload); final List frames = new ArrayList<>(); - Generator.Result result = generator.generatePing(payload, true); + ByteBufferPool.Lease lease = generator.generatePing(payload, true); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -93,7 +93,7 @@ public class PingGenerateParseTest } }); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index dcffe449e6a..e094bdd5685 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -47,7 +47,7 @@ public class PriorityGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - Generator.Result result = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); + ByteBufferPool.Lease lease = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -59,7 +59,7 @@ public class PriorityGenerateParseTest }); frames.clear(); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { @@ -87,7 +87,7 @@ public class PriorityGenerateParseTest boolean exclusive = true; final List frames = new ArrayList<>(); - Generator.Result result = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); + ByteBufferPool.Lease lease = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -98,7 +98,7 @@ public class PriorityGenerateParseTest } }); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index 2f946031466..69f27bd1135 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -45,7 +45,7 @@ public class ResetGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - Generator.Result result = generator.generateReset(streamId, error); + ByteBufferPool.Lease lease = generator.generateReset(streamId, error); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -57,7 +57,7 @@ public class ResetGenerateParseTest }); frames.clear(); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { @@ -81,7 +81,7 @@ public class ResetGenerateParseTest int error = 17; final List frames = new ArrayList<>(); - Generator.Result result = generator.generateReset(streamId, error); + ByteBufferPool.Lease lease = generator.generateReset(streamId, error); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -92,7 +92,7 @@ public class ResetGenerateParseTest } }); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index f52f383b3e9..9e07554ad31 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -75,7 +75,7 @@ public class SettingsGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - Generator.Result result = generator.generateSettings(settings, true); + ByteBufferPool.Lease lease = generator.generateSettings(settings, true); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -87,7 +87,7 @@ public class SettingsGenerateParseTest }); frames.clear(); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { @@ -105,9 +105,9 @@ public class SettingsGenerateParseTest Generator generator = new Generator(byteBufferPool); Map settings1 = new HashMap<>(); settings1.put(13, 17); - Generator.Result result = generator.generateSettings(settings1, true); + ByteBufferPool.Lease lease = generator.generateSettings(settings1, true); // Modify the length of the frame to make it invalid - ByteBuffer bytes = result.getByteBuffers().get(0); + ByteBuffer bytes = lease.getByteBuffers().get(0); bytes.putShort(0, (short)(bytes.getShort(0) - 1)); final AtomicInteger errorRef = new AtomicInteger(); @@ -120,7 +120,7 @@ public class SettingsGenerateParseTest } }); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { @@ -142,7 +142,7 @@ public class SettingsGenerateParseTest settings1.put(key, value); final List frames = new ArrayList<>(); - Generator.Result result = generator.generateSettings(settings1, true); + ByteBufferPool.Lease lease = generator.generateSettings(settings1, true); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -153,7 +153,7 @@ public class SettingsGenerateParseTest } }); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java index cfb9816af6e..273b59a148f 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java +++ b/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java @@ -45,7 +45,7 @@ public class WindowUpdateGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - Generator.Result result = generator.generateWindowUpdate(streamId, windowUpdate); + ByteBufferPool.Lease lease = generator.generateWindowUpdate(streamId, windowUpdate); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -57,7 +57,7 @@ public class WindowUpdateGenerateParseTest }); frames.clear(); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { @@ -81,7 +81,7 @@ public class WindowUpdateGenerateParseTest int windowUpdate = 17; final List frames = new ArrayList<>(); - Generator.Result result = generator.generateWindowUpdate(streamId, windowUpdate); + ByteBufferPool.Lease lease = generator.generateWindowUpdate(streamId, windowUpdate); Parser parser = new Parser(new Parser.Listener.Adapter() { @Override @@ -92,7 +92,7 @@ public class WindowUpdateGenerateParseTest } }); - for (ByteBuffer buffer : result.getByteBuffers()) + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) { From 58ed30e7103f1c86d1da9702e918795b30b93a27 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Sun, 8 Jun 2014 11:09:56 +0200 Subject: [PATCH 023/269] header table mostly functional --- .../java/org/eclipse/jetty/hpack/Field.java | 22 +- .../org/eclipse/jetty/hpack/HeaderTable.java | 91 ----- .../org/eclipse/jetty/hpack/HpackContext.java | 324 ++++++++++++++++++ .../eclipse/jetty/hpack/HpackContextTest.java | 120 +++++++ .../org/eclipse/jetty/http/HttpField.java | 28 +- .../org/eclipse/jetty/http/HttpFields.java | 2 +- .../org/eclipse/jetty/util/ArrayQueue.java | 54 +-- 7 files changed, 516 insertions(+), 125 deletions(-) delete mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HeaderTable.java create mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java create mode 100644 jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java index 6c0cd5b1803..259e55a79c4 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java @@ -29,6 +29,7 @@ public class Field extends HttpField { // final ByteBuffer _nameLiteral; // final ByteBuffer _nameHuffman; + private final NameKey _nameKey=new NameKey(); public Field(String name,String value) { @@ -66,8 +67,27 @@ public class Field extends HttpField _nameHuffman.position(_nameHuffman.limit()); BufferUtil.flipToFlush(_nameHuffman,0); */ - } + + public NameKey getNameKey() + { + return _nameKey; + } + + public class NameKey + { + + public Field getField() + { + return Field.this; + } + + @Override + public String toString() + { + return getName(); + } + }; } diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HeaderTable.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HeaderTable.java deleted file mode 100644 index e7c368d1932..00000000000 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HeaderTable.java +++ /dev/null @@ -1,91 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.hpack; - -public class HeaderTable -{ - - private static final String[][] STATIC_TABLE = - { - {null,null}, - /* 1 */ {":authority" ,""}, - /* 2 */ {":method" ,"GET"}, - /* 3 */ {":method" ,"POST"}, - /* 4 */ {":path" ,"/"}, - /* 5 */ {":path" ,"/index.html"}, - /* 6 */ {":scheme" ,"http"}, - /* 7 */ {":scheme" ,"https"}, - /* 8 */ {":status" ,"200"}, - /* 9 */ {":status" ,"204"}, - /* 10 */ {":status" ,"206"}, - /* 11 */ {":status" ,"304"}, - /* 12 */ {":status" ,"400"}, - /* 13 */ {":status" ,"404"}, - /* 14 */ {":status" ,"500"}, - /* 15 */ {"accept-charset" ,""}, - /* 16 */ {"accept-encoding" ,""}, - /* 17 */ {"accept-language" ,""}, - /* 18 */ {"accept-ranges" ,""}, - /* 19 */ {"accept" ,""}, - /* 20 */ {"access-control-allow-origin" ,""}, - /* 21 */ {"age" ,""}, - /* 22 */ {"allow" ,""}, - /* 23 */ {"authorization" ,""}, - /* 24 */ {"cache-control" ,""}, - /* 25 */ {"content-disposition" ,""}, - /* 26 */ {"content-encoding" ,""}, - /* 27 */ {"content-language" ,""}, - /* 28 */ {"content-length" ,""}, - /* 29 */ {"content-location" ,""}, - /* 30 */ {"content-range" ,""}, - /* 31 */ {"content-type" ,""}, - /* 32 */ {"cookie" ,""}, - /* 33 */ {"date" ,""}, - /* 34 */ {"etag" ,""}, - /* 35 */ {"expect" ,""}, - /* 36 */ {"expires" ,""}, - /* 37 */ {"from" ,""}, - /* 38 */ {"host" ,""}, - /* 39 */ {"if-match" ,""}, - /* 40 */ {"if-modified-since" ,""}, - /* 41 */ {"if-none-match" ,""}, - /* 42 */ {"if-range" ,""}, - /* 43 */ {"if-unmodified-since" ,""}, - /* 44 */ {"last-modified" ,""}, - /* 45 */ {"link" ,""}, - /* 46 */ {"location" ,""}, - /* 47 */ {"max-forwards" ,""}, - /* 48 */ {"proxy-authenticate" ,""}, - /* 49 */ {"proxy-authorization" ,""}, - /* 50 */ {"range" ,""}, - /* 51 */ {"referer" ,""}, - /* 52 */ {"refresh" ,""}, - /* 53 */ {"retry-after" ,""}, - /* 54 */ {"server" ,""}, - /* 55 */ {"set-cookie" ,""}, - /* 56 */ {"strict-transport-security" ,""}, - /* 57 */ {"transfer-encoding" ,""}, - /* 58 */ {"user-agent" ,""}, - /* 59 */ {"vary" ,""}, - /* 60 */ {"via" ,""}, - /* 61 */ {"www-authenticate" ,""}, - - }; - -} diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java new file mode 100644 index 00000000000..77d8c342e2c --- /dev/null +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java @@ -0,0 +1,324 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.hpack; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jetty.hpack.Field.NameKey; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.util.ArrayQueue; +import org.eclipse.jetty.util.ArrayTrie; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.Trie; + +public class HpackContext +{ + private static final String[][] STATIC_TABLE = + { + {null,null}, + /* 1 */ {":authority" ,null}, + /* 2 */ {":method" ,"GET"}, + /* 3 */ {":method" ,"POST"}, + /* 4 */ {":path" ,"/"}, + /* 5 */ {":path" ,"/index.html"}, + /* 6 */ {":scheme" ,"http"}, + /* 7 */ {":scheme" ,"https"}, + /* 8 */ {":status" ,"200"}, + /* 9 */ {":status" ,"204"}, + /* 10 */ {":status" ,"206"}, + /* 11 */ {":status" ,"304"}, + /* 12 */ {":status" ,"400"}, + /* 13 */ {":status" ,"404"}, + /* 14 */ {":status" ,"500"}, + /* 15 */ {"accept-charset" ,null}, + /* 16 */ {"accept-encoding" ,null}, + /* 17 */ {"accept-language" ,null}, + /* 18 */ {"accept-ranges" ,null}, + /* 19 */ {"accept" ,null}, + /* 20 */ {"access-control-allow-origin" ,null}, + /* 21 */ {"age" ,null}, + /* 22 */ {"allow" ,null}, + /* 23 */ {"authorization" ,null}, + /* 24 */ {"cache-control" ,null}, + /* 25 */ {"content-disposition" ,null}, + /* 26 */ {"content-encoding" ,null}, + /* 27 */ {"content-language" ,null}, + /* 28 */ {"content-length" ,null}, + /* 29 */ {"content-location" ,null}, + /* 30 */ {"content-range" ,null}, + /* 31 */ {"content-type" ,null}, + /* 32 */ {"cookie" ,null}, + /* 33 */ {"date" ,null}, + /* 34 */ {"etag" ,null}, + /* 35 */ {"expect" ,null}, + /* 36 */ {"expires" ,null}, + /* 37 */ {"from" ,null}, + /* 38 */ {"host" ,null}, + /* 39 */ {"if-match" ,null}, + /* 40 */ {"if-modified-since" ,null}, + /* 41 */ {"if-none-match" ,null}, + /* 42 */ {"if-range" ,null}, + /* 43 */ {"if-unmodified-since" ,null}, + /* 44 */ {"last-modified" ,null}, + /* 45 */ {"link" ,null}, + /* 46 */ {"location" ,null}, + /* 47 */ {"max-forwards" ,null}, + /* 48 */ {"proxy-authenticate" ,null}, + /* 49 */ {"proxy-authorization" ,null}, + /* 50 */ {"range" ,null}, + /* 51 */ {"referer" ,null}, + /* 52 */ {"refresh" ,null}, + /* 53 */ {"retry-after" ,null}, + /* 54 */ {"server" ,null}, + /* 55 */ {"set-cookie" ,null}, + /* 56 */ {"strict-transport-security" ,null}, + /* 57 */ {"transfer-encoding" ,null}, + /* 58 */ {"user-agent" ,null}, + /* 59 */ {"vary" ,null}, + /* 60 */ {"via" ,null}, + /* 61 */ {"www-authenticate" ,null}, + + }; + + private static final Map __staticFieldMap = new HashMap<>(); + private static final Trie __staticNameMap = new ArrayTrie<>(24); + + private static final Entry[] __staticTable=new Entry[STATIC_TABLE.length]; + static + { + Set added = new HashSet<>(); + for (int i=1;i _headerTable; + private final Map _fieldMap = new HashMap<>(); + private final Map _nameMap = new HashMap<>(); + + + HpackContext(int maxHeaderTableSize) + { + _maxHeaderTableSize=maxHeaderTableSize; + int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10); + _headerTable=new HeaderTable(guesstimateEntries,guesstimateEntries+10); + } + + public Entry get(HttpField field) + { + System.err.println(field); + System.err.println(_fieldMap); + System.err.println(__staticFieldMap); + Entry entry = _fieldMap.get(field); + if (entry==null) + entry=__staticFieldMap.get(field); + return entry; + } + + public Entry getNameEntry(String name) + { + Entry entry = __staticNameMap.get(name); + if (entry!=null) + return entry; + return _nameMap.get(StringUtil.asciiToLowerCase(name)); + } + + public Entry add(HttpField field) + { + int i=_headerTable.getNextIndexUnsafe(); + Entry entry=new Entry(i,field,false); + int size = entry.getSize(); + if (size>_maxHeaderTableSize) + return null; + _headerTableSize+=size; + _headerTable.addUnsafe(entry); + _fieldMap.put(field,entry); + _nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry); + + evict(); + return entry; + } + + public void evict() + { + while (_headerTableSize>_maxHeaderTableSize) + { + Entry entry = _headerTable.pollUnsafe(); + _headerTableSize-=entry.getSize(); + entry.removeFromRefSet(); + _fieldMap.remove(entry.getHttpField()); + String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName()); + if (entry==_nameMap.get(lc)) + _nameMap.remove(lc); + } + } + + + + + /* ------------------------------------------------------------ */ + /** + */ + private class HeaderTable extends ArrayQueue + { + /* ------------------------------------------------------------ */ + /** + * @param initCapacity + * @param growBy + */ + private HeaderTable(int initCapacity, int growBy) + { + super(initCapacity,growBy); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.util.ArrayQueue#growUnsafe() + */ + @Override + protected void growUnsafe(int newCapacity) + { + // Relay on super.growUnsafe to pack all entries 0 to _nextSlot + super.growUnsafe(newCapacity); + for (int i=0;i<_nextSlot;i++) + ((Entry)_elements[i])._index=i; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.util.ArrayQueue#enqueue(java.lang.Object) + */ + @Override + public boolean enqueue(Entry e) + { + return super.enqueue(e); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.util.ArrayQueue#dequeue() + */ + @Override + public Entry dequeue() + { + return super.dequeue(); + } + } + + + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + public static class Entry + { + int _index; + final boolean _static; + final HttpField _field; + Entry _refSetNext=this; + Entry _refSetPrev=this; + boolean _refSetUsed; + + Entry(boolean isStatic) + { + _static=isStatic; + _index=0; + _field=null; + } + + Entry(int index,String name, String value, boolean isStatic) + { + _static=isStatic; + _index=index; + _field=new HttpField(name,value); + } + + Entry(int index, HttpField field, boolean isStatic) + { + _static=isStatic; + _index=index; + _field=field; + } + + public void addToRefSet(HpackContext ctx) + { + _refSetNext=ctx._refSet; + _refSetPrev=ctx._refSet._refSetPrev; + ctx._refSet._refSetPrev._refSetNext=this; + ctx._refSet._refSetPrev=this; + } + + public void removeFromRefSet() + { + if (_refSetNext!=this) + { + _refSetNext._refSetPrev=_refSetPrev; + _refSetPrev._refSetNext=_refSetNext; + _refSetNext=this; + _refSetPrev=this; + } + } + + public int getSize() + { + return 32+_field.getName().length()+_field.getValue().length(); + } + + /** + * @return + */ + public HttpField getHttpField() + { + return _field; + } + + /** + * @return + */ + public boolean isStatic() + { + return _static; + } + + public String toString() + { + return String.format("{%s,%d,%s,%x}",_static?"S":"D",_index,_field,hashCode()); + } + } + + + + + +} diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java new file mode 100644 index 00000000000..ad908995a04 --- /dev/null +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java @@ -0,0 +1,120 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.eclipse.jetty.hpack.HpackContext.Entry; +import org.eclipse.jetty.http.HttpField; +import org.junit.Assert; +import org.junit.Test; + + +/* ------------------------------------------------------------ */ +/** + */ +public class HpackContextTest +{ + + @Test + public void testStaticName() + { + HpackContext ctx = new HpackContext(4096); + Entry entry=ctx.getNameEntry(":method"); + assertEquals(":method",entry.getHttpField().getName()); + Assert.assertTrue(entry.isStatic()); + } + + @Test + public void testEmptyAdd() + { + HpackContext ctx = new HpackContext(0); + HttpField field = new HttpField("foo","bar"); + Assert.assertNull(ctx.add(field)); + } + + @Test + public void testTooBigAdd() + { + HpackContext ctx = new HpackContext(37); + HttpField field = new HttpField("foo","bar"); + Assert.assertNull(ctx.add(field)); + } + + @Test + public void testJustRight() + { + HpackContext ctx = new HpackContext(38); + HttpField field = new HttpField("foo","bar"); + Assert.assertNotNull(ctx.add(field)); + } + + @Test + public void testEvictOne() + { + HpackContext ctx = new HpackContext(38); + HttpField field0 = new HttpField("foo","bar"); + + assertEquals(field0,ctx.add(field0).getHttpField()); + assertEquals(field0,ctx.getNameEntry("foo").getHttpField()); + + HttpField field1 = new HttpField("xxx","yyy"); + assertEquals(field1,ctx.add(field1).getHttpField()); + + assertNull(ctx.get(field0)); + assertNull(ctx.getNameEntry("foo")); + assertEquals(field1,ctx.get(field1).getHttpField()); + assertEquals(field1,ctx.getNameEntry("xxx").getHttpField()); + + } + + @Test + public void testGetAddStatic() + { + HpackContext ctx = new HpackContext(4096); + + // Look for the field. Should find static version. + HttpField methodGet = new HttpField(":method","GET"); + assertEquals(methodGet,ctx.get(methodGet).getHttpField()); + assertTrue(ctx.get(methodGet).isStatic()); + + // Add static version to header table + Entry e0=ctx.add(ctx.get(methodGet).getHttpField()); + + // Look again and should see dynamic version + assertEquals(methodGet,ctx.get(methodGet).getHttpField()); + assertFalse(methodGet==ctx.get(methodGet).getHttpField()); + assertFalse(ctx.get(methodGet).isStatic()); + + // Duplicates allows + Entry e1=ctx.add(ctx.get(methodGet).getHttpField()); + + // Look again and should see dynamic version + assertEquals(methodGet,ctx.get(methodGet).getHttpField()); + assertFalse(methodGet==ctx.get(methodGet).getHttpField()); + assertFalse(ctx.get(methodGet).isStatic()); + assertFalse(e0==e1); + } + +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index aa7a63a8f1f..f270482f3a9 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -72,7 +72,7 @@ public class HttpField return getName() + ": " + (v==null?"":v); } - public boolean isSame(HttpField field) + public boolean isSameName(HttpField field) { if (field==null) return false; @@ -103,22 +103,28 @@ public class HttpField return false; return true; } + + public int nameHashCode() + { + int hash=13; + int len = _name.length(); + for (int i = 0; i < len; i++) + { + char c = Character.toUpperCase(_name.charAt(i)); + hash = 31 * hash + c; + } + return hash; + } @Override public int hashCode() { if (_header==null) - { - int hash=13; - int len = _name.length(); - for (int i = 0; i < len; i++) - { - char c = Character.toUpperCase(_name.charAt(i)); - hash = 31 * hash + c; - } - return _value.hashCode() ^ hash; - } + return _value.hashCode() ^ nameHashCode(); return _value.hashCode() ^ _header.hashCode(); } + + + } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index d4742274530..8de9f5f6e83 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -333,7 +333,7 @@ public class HttpFields implements Iterable for (int i=_fields.size();i-->0;) { HttpField f=_fields.get(i); - if (f.isSame(field)) + if (f.isSameName(field)) { if (put) _fields.remove(i); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java index 671439e5923..6b4e5950847 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java @@ -90,6 +90,15 @@ public class ArrayQueue extends AbstractList implements Queue } } + /* ------------------------------------------------------------ */ + /** + * @return the next index to be used + */ + public int getNextIndexUnsafe() + { + return _nextSlot; + } + /* ------------------------------------------------------------ */ @Override public boolean add(E e) @@ -109,9 +118,9 @@ public class ArrayQueue extends AbstractList implements Queue } /* ------------------------------------------------------------ */ - private boolean enqueue(E e) + protected boolean enqueue(E e) { - if (_size == _elements.length && !grow()) + if (_size == _elements.length && !growUnsafe()) return false; _size++; @@ -192,7 +201,7 @@ public class ArrayQueue extends AbstractList implements Queue } /* ------------------------------------------------------------ */ - private E dequeue() + protected E dequeue() { E e = at(_nextE); _elements[_nextE] = null; @@ -339,7 +348,7 @@ public class ArrayQueue extends AbstractList implements Queue if (index < 0 || index > _size) throw new IndexOutOfBoundsException("!(" + 0 + "<" + index + "<=" + _size + ")"); - if (_size == _elements.length && !grow()) + if (_size == _elements.length && !growUnsafe()) throw new IllegalStateException("Full"); if (index == _size) @@ -384,25 +393,28 @@ public class ArrayQueue extends AbstractList implements Queue } /* ------------------------------------------------------------ */ - protected boolean grow() + protected void growUnsafe(int newCapacity) { - synchronized (_lock) - { - if (_growCapacity <= 0) - return false; + Object[] elements = new Object[newCapacity]; - Object[] elements = new Object[_elements.length + _growCapacity]; + int split = _elements.length - _nextE; + if (split > 0) + System.arraycopy(_elements, _nextE, elements, 0, split); + if (_nextE != 0) + System.arraycopy(_elements, 0, elements, split, _nextSlot); - int split = _elements.length - _nextE; - if (split > 0) - System.arraycopy(_elements, _nextE, elements, 0, split); - if (_nextE != 0) - System.arraycopy(_elements, 0, elements, split, _nextSlot); - - _elements = elements; - _nextE = 0; - _nextSlot = _size; - return true; - } + _elements = elements; + _nextE = 0; + _nextSlot = _size; } + + /* ------------------------------------------------------------ */ + protected boolean growUnsafe() + { + if (_growCapacity <= 0) + return false; + growUnsafe(_elements.length+_growCapacity); + return true; + } + } From ae4dea3e1e797ec23fb9e952fb7babed7c2a00ef Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Sun, 8 Jun 2014 15:17:39 +0200 Subject: [PATCH 024/269] near 100% test coverage of NBitInteger, Huffman and HpackContext --- .../org/eclipse/jetty/hpack/HpackContext.java | 148 +++++- .../java/org/eclipse/jetty/hpack/Huffman.java | 6 +- .../org/eclipse/jetty/hpack/NBitInteger.java | 40 +- .../eclipse/jetty/hpack/HpackContextTest.java | 497 +++++++++++++++++- .../org/eclipse/jetty/hpack/HuffmanTest.java | 42 +- .../eclipse/jetty/hpack/NBitIntegerTest.java | 28 +- .../org/eclipse/jetty/util/ArrayQueue.java | 23 +- 7 files changed, 735 insertions(+), 49 deletions(-) diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java index 77d8c342e2c..d45ce9fec50 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java @@ -20,10 +20,11 @@ package org.eclipse.jetty.hpack; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; -import org.eclipse.jetty.hpack.Field.NameKey; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.ArrayTrie; @@ -108,8 +109,7 @@ public class HpackContext Set added = new HashSet<>(); for (int i=1;i _headerTable; + private final HeaderTable _headerTable; private final Map _fieldMap = new HashMap<>(); private final Map _nameMap = new HashMap<>(); + private Iterable referenceSet = new Iterable() + { + @Override + public Iterator iterator() + { + return iterateReferenceSet(); + } + }; HpackContext(int maxHeaderTableSize) { - _maxHeaderTableSize=maxHeaderTableSize; + _maxHeaderTableSizeInBytes=maxHeaderTableSize; int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10); _headerTable=new HeaderTable(guesstimateEntries,guesstimateEntries+10); } + public void resize(int maxHeaderTableSize) + { + _maxHeaderTableSizeInBytes=maxHeaderTableSize; + int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10); + evict(); + _headerTable.resizeUnsafe(guesstimateEntries); + } + public Entry get(HttpField field) { - System.err.println(field); - System.err.println(_fieldMap); - System.err.println(__staticFieldMap); Entry entry = _fieldMap.get(field); if (entry==null) entry=__staticFieldMap.get(field); return entry; } - public Entry getNameEntry(String name) + public Entry get(String name) { Entry entry = __staticNameMap.get(name); if (entry!=null) @@ -154,14 +167,27 @@ public class HpackContext return _nameMap.get(StringUtil.asciiToLowerCase(name)); } + public Entry get(int index) + { + index=index-_headerTable.size(); + if (index>0) + { + if (index>=__staticTable.length) + return null; + return __staticTable[index]; + } + + return _headerTable.getUnsafe(-index); + } + public Entry add(HttpField field) { int i=_headerTable.getNextIndexUnsafe(); Entry entry=new Entry(i,field,false); int size = entry.getSize(); - if (size>_maxHeaderTableSize) + if (size>_maxHeaderTableSizeInBytes) return null; - _headerTableSize+=size; + _headerTableSizeInBytes+=size; _headerTable.addUnsafe(entry); _fieldMap.put(field,entry); _nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry); @@ -169,14 +195,72 @@ public class HpackContext evict(); return entry; } - - public void evict() + + public Object size() { - while (_headerTableSize>_maxHeaderTableSize) + return _headerTable.size(); + } + + public int index(Entry entry) + { + if (entry._index<0) + return 0; + if (entry.isStatic()) + return _headerTable.size() + entry._index; + return _headerTable.index(entry); + } + + public void addToRefSet(Entry entry) + { + entry.addToRefSet(this); + } + + public Iterable getReferenceSet() + { + return referenceSet; + } + + public Iterator iterateReferenceSet() + { + return new Iterator() + { + Entry _next = _refSet._refSetNext; + + @Override + public boolean hasNext() + { + return _next!=_refSet; + } + + @Override + public Entry next() + { + if (_next==_refSet) + throw new NoSuchElementException(); + Entry next=_next; + _next=_next._refSetNext; + return next; + } + + @Override + public void remove() + { + if (_next._refSetPrev==_refSet) + throw new NoSuchElementException(); + + _next._refSetPrev.removeFromRefSet(); + } + }; + } + + private void evict() + { + while (_headerTableSizeInBytes>_maxHeaderTableSizeInBytes) { Entry entry = _headerTable.pollUnsafe(); - _headerTableSize-=entry.getSize(); + _headerTableSizeInBytes-=entry.getSize(); entry.removeFromRefSet(); + entry._index=-1; _fieldMap.remove(entry.getHttpField()); String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName()); if (entry==_nameMap.get(lc)) @@ -207,10 +291,10 @@ public class HpackContext * @see org.eclipse.jetty.util.ArrayQueue#growUnsafe() */ @Override - protected void growUnsafe(int newCapacity) + protected void resizeUnsafe(int newCapacity) { // Relay on super.growUnsafe to pack all entries 0 to _nextSlot - super.growUnsafe(newCapacity); + super.resizeUnsafe(newCapacity); for (int i=0;i<_nextSlot;i++) ((Entry)_elements[i])._index=i; } @@ -234,6 +318,17 @@ public class HpackContext { return super.dequeue(); } + + /* ------------------------------------------------------------ */ + /** + * @param entry + * @return + */ + private int index(Entry entry) + { + return entry._index>=_nextE?_size-entry._index+_nextE:_nextSlot-entry._index; + } + } @@ -271,8 +366,15 @@ public class HpackContext _field=field; } - public void addToRefSet(HpackContext ctx) + private void addToRefSet(HpackContext ctx) { + if (_static) + throw new IllegalStateException("static"); + if (_index<0) + throw new IllegalStateException("evicted"); + if (_refSetNext!=this) + return; + _refSetNext=ctx._refSet; _refSetPrev=ctx._refSet._refSetPrev; ctx._refSet._refSetPrev._refSetNext=this; @@ -316,9 +418,7 @@ public class HpackContext return String.format("{%s,%d,%s,%x}",_static?"S":"D",_index,_field,hashCode()); } } - - - - + + } diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java index a3f50dab39c..e21fbd00e2f 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java @@ -316,8 +316,6 @@ public class Huffman { len -= 8; int i = ((code >>> len) & 0xFF); - if (rowbits[current]!=0) - throw new IllegalStateException("invalid dictionary: prefix not unique"); int t=current*256+i; current = tree[t]; @@ -404,7 +402,7 @@ public class Huffman for (int i=0;i=128) + if (c>=128 || c<' ') throw new IllegalArgumentException(); needed += CODES[c][1]; } @@ -424,7 +422,7 @@ public class Huffman for (int i=0;i=128) + if (c>=128 || c<' ') throw new IllegalArgumentException(); int code = CODES[c][0]; int bits = CODES[c][1]; diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java index 6be6e9b3bd1..b3b2aee45a6 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java @@ -24,12 +24,25 @@ public class NBitInteger { public static int octectsNeeded(int n,int i) { + if (n==8) + { + int nbits = 0xFF; + i=i-nbits; + if (i<0) + return 1; + if (i==0) + return 2; + int lz=Integer.numberOfLeadingZeros(i); + int log=32-lz; + return 1+(log+6)/7; + } + int nbits = 0xFF >>> (8 - n); i=i-nbits; if (i<0) - return n==8?1:0; + return 0; if (i==0) - return n==8?2:1; + return 1; int lz=Integer.numberOfLeadingZeros(i); int log=32-lz; return (log+6)/7; @@ -96,9 +109,30 @@ public class NBitInteger public static int decode(ByteBuffer buf, int n) { + if (n==8) + { + int nbits = 0xFF; + + int i=buf.get()&0xff; + + if (i == nbits) + { + int m=1; + int b; + do + { + b = 0xff&buf.get(); + i = i + (b&127) * m; + m = m*128; + } + while ((b&128) == 128); + } + return i; + } + int nbits = 0xFF >>> (8 - n); - int i=buf.get(buf.position()-(n==8?0:1))&nbits; + int i=buf.get(buf.position()-1)&nbits; if (i == nbits) { diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java index ad908995a04..b4e7db529c6 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java @@ -24,9 +24,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.NoSuchElementException; import org.eclipse.jetty.hpack.HpackContext.Entry; import org.eclipse.jetty.http.HttpField; +import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; @@ -41,9 +47,10 @@ public class HpackContextTest public void testStaticName() { HpackContext ctx = new HpackContext(4096); - Entry entry=ctx.getNameEntry(":method"); + Entry entry=ctx.get(":method"); assertEquals(":method",entry.getHttpField().getName()); Assert.assertTrue(entry.isStatic()); + Assert.assertThat(entry.toString(),Matchers.startsWith("{S,2,:method: ")); } @Test @@ -67,7 +74,9 @@ public class HpackContextTest { HpackContext ctx = new HpackContext(38); HttpField field = new HttpField("foo","bar"); - Assert.assertNotNull(ctx.add(field)); + Entry entry=ctx.add(field); + Assert.assertNotNull(entry); + Assert.assertThat(entry.toString(),Matchers.startsWith("{D,0,foo: bar,")); } @Test @@ -77,18 +86,53 @@ public class HpackContextTest HttpField field0 = new HttpField("foo","bar"); assertEquals(field0,ctx.add(field0).getHttpField()); - assertEquals(field0,ctx.getNameEntry("foo").getHttpField()); + assertEquals(field0,ctx.get("foo").getHttpField()); HttpField field1 = new HttpField("xxx","yyy"); assertEquals(field1,ctx.add(field1).getHttpField()); assertNull(ctx.get(field0)); - assertNull(ctx.getNameEntry("foo")); + assertNull(ctx.get("foo")); assertEquals(field1,ctx.get(field1).getHttpField()); - assertEquals(field1,ctx.getNameEntry("xxx").getHttpField()); + assertEquals(field1,ctx.get("xxx").getHttpField()); } - + + @Test + public void testEvictNames() + { + HpackContext ctx = new HpackContext(38*2); + HttpField[] field = + { + new HttpField("name","v0"), + new HttpField("name","v1"), + new HttpField("name","v2"), + new HttpField("name","v3"), + new HttpField("name","v4"), + new HttpField("name","v5"), + }; + + Entry[] entry = new Entry[field.length]; + + // Add 2 name entries to fill table + for (int i=0;i<=1;i++) + entry[i]=ctx.add(field[i]); + + // check there is a name reference and it is the most recent added + assertEquals(entry[1],ctx.get("name")); + + // Add 1 other entry to table and evict 1 + ctx.add(new HttpField("xxx","yyy")); + + // check the name reference has been not been evicted + assertEquals(entry[1],ctx.get("name")); + + // Add 1 other entry to table and evict 1 + ctx.add(new HttpField("foo","bar")); + + // name is evicted + assertNull(ctx.get("name")); + } @Test public void testGetAddStatic() { @@ -116,5 +160,446 @@ public class HpackContextTest assertFalse(ctx.get(methodGet).isStatic()); assertFalse(e0==e1); } + + @Test + public void testGetAddStaticName() + { + HpackContext ctx = new HpackContext(4096); + HttpField methodOther = new HttpField(":method","OTHER"); + // Look for the field by name. Should find static version. + assertEquals(":method",ctx.get(":method").getHttpField().getName()); + assertTrue(ctx.get(":method").isStatic()); + + // Add dynamic entry with method + ctx.add(methodOther); + + // Look for the field by name. Should find static version. + assertEquals(":method",ctx.get(":method").getHttpField().getName()); + assertTrue(ctx.get(":method").isStatic()); + } + + @Test + public void testIndexes() + { + // Only enough space for 5 entries + HpackContext ctx = new HpackContext(38*5); + + HttpField methodPost = new HttpField(":method","POST"); + HttpField[] field = + { + new HttpField("fo0","b0r"), + new HttpField("fo1","b1r"), + new HttpField("fo2","b2r"), + new HttpField("fo3","b3r"), + new HttpField("fo4","b4r"), + new HttpField("fo5","b5r"), + new HttpField("fo6","b6r"), + new HttpField("fo7","b7r"), + new HttpField("fo8","b8r"), + new HttpField("fo9","b9r"), + new HttpField("foA","bAr"), + }; + + Entry[] entry = new Entry[100]; + + // Lookup the index of a static field + assertEquals(0,ctx.size()); + assertEquals(":authority",ctx.get(1).getHttpField().getName()); + assertEquals(3,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3).getHttpField()); + assertEquals("www-authenticate",ctx.get(61).getHttpField().getName()); + assertEquals(null,ctx.get(62)); + + // Add a single entry + entry[0]=ctx.add(field[0]); + + // Check new entry is 1 + assertEquals(1,ctx.size()); + assertEquals(1,ctx.index(entry[0])); + assertEquals(entry[0],ctx.get(1)); + + // and statics have moved up 1 + assertEquals(":authority",ctx.get(1+1).getHttpField().getName()); + assertEquals(3+1,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+1).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+1).getHttpField().getName()); + assertEquals(null,ctx.get(62+1)); + + + // Add 4 more entries + for (int i=1;i<=4;i++) + entry[i]=ctx.add(field[i]); + + // Check newest entry is at 1 oldest at 5 + assertEquals(5,ctx.size()); + int index=5; + for (int i=0;i<=4;i++) + { + assertEquals(index,ctx.index(entry[i])); + assertEquals(entry[i],ctx.get(index)); + index--; + } + + // and statics have moved up 5 + assertEquals(":authority",ctx.get(1+5).getHttpField().getName()); + assertEquals(3+5,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+5).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName()); + assertEquals(null,ctx.get(62+5)); + + // add 1 more entry and this should cause an eviction! + entry[5]=ctx.add(field[5]); + + // Check newest entry is at 1 oldest at 5 + index=5; + for (int i=1;i<=5;i++) + { + assertEquals(index,ctx.index(entry[i])); + assertEquals(entry[i],ctx.get(index)); + index--; + } + // check entry 0 evicted + assertNull(ctx.get(field[0])); + assertEquals(0,ctx.index(entry[0])); + + // and statics have moved up just 5 + assertEquals(":authority",ctx.get(1+5).getHttpField().getName()); + assertEquals(3+5,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+5).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName()); + assertEquals(null,ctx.get(62+5)); + + // Add 4 more entries + for (int i=6;i<=9;i++) + entry[i]=ctx.add(field[i]); + + // Check newest entry is at 1 oldest at 5 + index=5; + for (int i=5;i<=9;i++) + { + assertEquals(index,ctx.index(entry[i])); + assertEquals(entry[i],ctx.get(index)); + index--; + } + // check entry 0-4 evicted + for (int i=0;i<=4;i++) + { + assertNull(ctx.get(field[i])); + assertEquals(0,ctx.index(entry[i])); + } + + + // Add new entries enough so that array queue will wrap + for (int i=10;i<=52;i++) + entry[i]=ctx.add(new HttpField("n"+i,"v"+i)); + + index=5; + for (int i=48;i<=52;i++) + { + assertEquals(index,ctx.index(entry[i])); + assertEquals(entry[i],ctx.get(index)); + index--; + } + } + + + @Test + public void testRefSetAddStatic() + { + try + { + HpackContext ctx = new HpackContext(4096); + + HttpField methodGet = new HttpField(":method","GET"); + Entry entry = ctx.get(methodGet); + ctx.addToRefSet(entry); + fail(); + } + catch(IllegalStateException e) + {} + } + + @Test + public void testRefSetAddEvicted() + { + try + { + HpackContext ctx = new HpackContext(38); + HttpField field0 = new HttpField("foo","bar"); + HttpField field1 = new HttpField("xxx","yyy"); + Entry entry = ctx.add(field0); + ctx.add(field1); + ctx.addToRefSet(entry); + fail(); + } + catch(IllegalStateException e) + {} + } + + @Test + public void testRefSetEmptyIteration() + { + HpackContext ctx = new HpackContext(4096); + for (Entry entry: ctx.getReferenceSet() ) + fail("unexpected:"+entry); + Iterator iter = ctx.iterateReferenceSet(); + assertFalse(iter.hasNext()); + + try + { + iter.next(); + fail(); + } + catch(NoSuchElementException e) + { + } + + try + { + iter.remove(); + fail(); + } + catch(NoSuchElementException e) + { + } + + } + + + @Test + public void testRefSet() + { + // Only enough space for 5 entries + HpackContext ctx = new HpackContext(38*5); + + HttpField[] field = + { + new HttpField("fo0","b0r"), + new HttpField("fo1","b1r"), + new HttpField("fo2","b2r"), + new HttpField("fo3","b3r"), + new HttpField("fo4","b4r"), + new HttpField("fo5","b5r"), + new HttpField("fo6","b6r"), + new HttpField("fo7","b7r"), + new HttpField("fo8","b8r"), + new HttpField("fo9","b9r"), + new HttpField("foA","bAr"), + }; + Entry[] entry = new Entry[field.length]; + + // Add 5 entries + for (int i=0;i<=4;i++) + entry[i]=ctx.add(field[i]); + + // Add 3 entries to reference set + ctx.addToRefSet(ctx.get(3)); + ctx.addToRefSet(ctx.get(1)); + ctx.addToRefSet(ctx.get(5)); + + // iterate ref set + HashSet fields = new HashSet<>(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(3,fields.size()); + assertTrue(fields.contains(field[0])); + assertTrue(fields.contains(field[2])); + assertTrue(fields.contains(field[4])); + + // duplicate add ignored + ctx.addToRefSet(ctx.get(1)); + fields.clear(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(3,fields.size()); + assertTrue(fields.contains(field[0])); + assertTrue(fields.contains(field[2])); + assertTrue(fields.contains(field[4])); + + // remove entry + ctx.get(3).removeFromRefSet(); + fields.clear(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(2,fields.size()); + assertTrue(fields.contains(field[0])); + assertTrue(fields.contains(field[4])); + + // iterator remove + Iterator iter=ctx.iterateReferenceSet(); + iter.next(); + iter.remove(); + fields.clear(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(1,fields.size()); + + // Add 5 new entries to cause evictions + for (int i=5;i<=9;i++) + entry[i]=ctx.add(field[i]); + fields.clear(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(0,fields.size()); + + } + + @Test + public void testResize() + { + // Only enough space for 5 entries + HpackContext ctx = new HpackContext(38*5); + HttpField methodPost = new HttpField(":method","POST"); + + HttpField[] field = + { + new HttpField("fo0","b0r"), + new HttpField("fo1","b1r"), + new HttpField("fo2","b2r"), + new HttpField("fo3","b3r"), + new HttpField("fo4","b4r"), + new HttpField("fo5","b5r"), + new HttpField("fo6","b6r"), + new HttpField("fo7","b7r"), + new HttpField("fo8","b8r"), + new HttpField("fo9","b9r"), + new HttpField("foA","bAr"), + }; + Entry[] entry = new Entry[field.length]; + + // Add 5 entries + for (int i=0;i<=4;i++) + entry[i]=ctx.add(field[i]); + + assertEquals(5,ctx.size()); + + // check indexes + int index=5; + for (int i=0;i<=4;i++) + { + assertEquals(index,ctx.index(entry[i])); + assertEquals(entry[i],ctx.get(index)); + index--; + } + + // and statics have moved up 5 + assertEquals(":authority",ctx.get(1+5).getHttpField().getName()); + assertEquals(3+5,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+5).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName()); + assertEquals(null,ctx.get(62+5)); + + + // Add 3 entries to reference set + ctx.addToRefSet(ctx.get(3)); + ctx.addToRefSet(ctx.get(1)); + ctx.addToRefSet(ctx.get(5)); + + + + // iterate ref set + HashSet fields = new HashSet<>(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(3,fields.size()); + assertTrue(fields.contains(field[0])); + assertTrue(fields.contains(field[2])); + assertTrue(fields.contains(field[4])); + + // resize so that only 2 entries may be held + ctx.resize(38*2); + assertEquals(2,ctx.size()); + + // check indexes + index=2; + for (int i=3;i<=4;i++) + { + assertEquals(index,ctx.index(entry[i])); + assertEquals(entry[i],ctx.get(index)); + index--; + } + + // and statics have moved up 2 + assertEquals(":authority",ctx.get(1+2).getHttpField().getName()); + assertEquals(3+2,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+2).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+2).getHttpField().getName()); + assertEquals(null,ctx.get(62+2)); + + // check reference set + fields.clear(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(1,fields.size()); + assertFalse(fields.contains(field[0])); + assertFalse(fields.contains(field[2])); + assertTrue(fields.contains(field[4])); + + + // resize so that 6.5 entries may be held + ctx.resize(38*6+19); + assertEquals(2,ctx.size()); + + + // check indexes + index=2; + for (int i=3;i<=4;i++) + { + assertEquals(index,ctx.index(entry[i])); + assertEquals(entry[i],ctx.get(index)); + index--; + } + + // and statics have moved up 2 + assertEquals(":authority",ctx.get(1+2).getHttpField().getName()); + assertEquals(3+2,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+2).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+2).getHttpField().getName()); + assertEquals(null,ctx.get(62+2)); + + // check reference set + fields.clear(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(1,fields.size()); + assertFalse(fields.contains(field[0])); + assertFalse(fields.contains(field[2])); + assertTrue(fields.contains(field[4])); + + + // Add 5 entries + for (int i=5;i<=9;i++) + entry[i]=ctx.add(field[i]); + + assertEquals(6,ctx.size()); + + // check indexes + index=6; + for (int i=4;i<=9;i++) + { + assertEquals(index,ctx.index(entry[i])); + assertEquals(entry[i],ctx.get(index)); + index--; + } + + // and statics have moved up 6 + assertEquals(":authority",ctx.get(1+6).getHttpField().getName()); + assertEquals(3+6,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+6).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+6).getHttpField().getName()); + assertEquals(null,ctx.get(62+6)); + + // check reference set + fields.clear(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(1,fields.size()); + assertFalse(fields.contains(field[0])); + assertFalse(fields.contains(field[2])); + assertTrue(fields.contains(field[4])); + + + + } } diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java index a68b16f2ebf..a6f19157ce2 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java @@ -51,6 +51,17 @@ public class HuffmanTest } } + @Test + public void testDecodeTrailingFF() throws Exception + { + for (String[] test:tests) + { + byte[] encoded=TypeUtil.fromHexString(test[1]+"FF"); + String decoded=Huffman.decode(ByteBuffer.wrap(encoded)); + Assert.assertEquals(test[0],test[2],decoded); + } + } + @Test public void testEncode() throws Exception { @@ -62,8 +73,37 @@ public class HuffmanTest BufferUtil.flipToFlush(buf,pos); String encoded=TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase(); Assert.assertEquals(test[0],test[1],encoded); + Assert.assertEquals(test[1].length()/2,Huffman.octetsNeeded(test[2])); + } + } + + @Test + public void testEncode8859Only() throws Exception + { + char bad[] = {(char)128,(char)0,(char)-1,' '-1}; + for (int i=0;i extends AbstractList implements Queue } /* ------------------------------------------------------------ */ - protected void growUnsafe(int newCapacity) + protected void resizeUnsafe(int newCapacity) { + newCapacity = Math.max(newCapacity,_size); Object[] elements = new Object[newCapacity]; - int split = _elements.length - _nextE; - if (split > 0) - System.arraycopy(_elements, _nextE, elements, 0, split); - if (_nextE != 0) - System.arraycopy(_elements, 0, elements, split, _nextSlot); - + if (_size>0) + { + if (_nextSlot>_nextE) + System.arraycopy(_elements, _nextE, elements, 0, _size); + else + { + int split = _elements.length - _nextE; + System.arraycopy(_elements, _nextE, elements, 0, split); + System.arraycopy(_elements, 0, elements, split, _nextSlot); + } + } _elements = elements; _nextE = 0; _nextSlot = _size; @@ -413,8 +419,7 @@ public class ArrayQueue extends AbstractList implements Queue { if (_growCapacity <= 0) return false; - growUnsafe(_elements.length+_growCapacity); + resizeUnsafe(_elements.length+_growCapacity); return true; } - } From 9e639d9236fa5234d5118e6cffb21c64dbe92201 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Sun, 8 Jun 2014 17:06:18 +0200 Subject: [PATCH 025/269] encoded static field --- .../org/eclipse/jetty/hpack/HpackContext.java | 89 ++++++++++++++---- .../org/eclipse/jetty/hpack/HpackEncoder.java | 56 +++++++++++- .../java/org/eclipse/jetty/hpack/Huffman.java | 2 +- .../eclipse/jetty/hpack/HpackContextTest.java | 90 ++++++++++++++++++- 4 files changed, 210 insertions(+), 27 deletions(-) diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java index d45ce9fec50..c3e28897706 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.hpack; +import java.nio.ByteBuffer; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -109,7 +110,7 @@ public class HpackContext Set added = new HashSet<>(); for (int i=1;i _fieldMap = new HashMap<>(); private final Map _nameMap = new HashMap<>(); @@ -183,7 +184,7 @@ public class HpackContext public Entry add(HttpField field) { int i=_headerTable.getNextIndexUnsafe(); - Entry entry=new Entry(i,field,false); + Entry entry=new Entry(i,field); int size = entry.getSize(); if (size>_maxHeaderTableSizeInBytes) return null; @@ -220,6 +221,17 @@ public class HpackContext return referenceSet; } + public void clearReferenceSet() + { + Entry entry = _refSet._refSetNext; + while(entry!=_refSet) + { + Entry next = entry._refSetNext; + entry.removeFromRefSet(); + entry=next; + } + } + public Iterator iterateReferenceSet() { return new Iterator() @@ -339,36 +351,32 @@ public class HpackContext public static class Entry { int _index; - final boolean _static; final HttpField _field; Entry _refSetNext=this; Entry _refSetPrev=this; boolean _refSetUsed; - Entry(boolean isStatic) + Entry() { - _static=isStatic; _index=0; _field=null; } - Entry(int index,String name, String value, boolean isStatic) + Entry(int index,String name, String value) { - _static=isStatic; _index=index; _field=new HttpField(name,value); } - Entry(int index, HttpField field, boolean isStatic) + Entry(int index, HttpField field) { - _static=isStatic; _index=index; _field=field; } private void addToRefSet(HpackContext ctx) { - if (_static) + if (isStatic()) throw new IllegalStateException("static"); if (_index<0) throw new IllegalStateException("evicted"); @@ -380,6 +388,11 @@ public class HpackContext ctx._refSet._refSetPrev._refSetNext=this; ctx._refSet._refSetPrev=this; } + + public boolean isInReferenceSet() + { + return _refSetNext!=this; + } public void removeFromRefSet() { @@ -397,25 +410,63 @@ public class HpackContext return 32+_field.getName().length()+_field.getValue().length(); } - /** - * @return - */ public HttpField getHttpField() { return _field; } - /** - * @return - */ public boolean isStatic() { - return _static; + return false; + } + + public byte[] getStaticHuffmanValue() + { + return null; } public String toString() { - return String.format("{%s,%d,%s,%x}",_static?"S":"D",_index,_field,hashCode()); + return String.format("{%s,%d,%s,%x}",isStatic()?"S":"D",_index,_field,hashCode()); + } + } + + public static class StaticEntry extends Entry + { + final byte[] _huffmanValue; + + StaticEntry(int index,String name, String value) + { + super(index,name,value); + if (value!=null && value.length()>0) + { + int huffmanLen = Huffman.octetsNeeded(value); + int lenLen = NBitInteger.octectsNeeded(7,huffmanLen); + _huffmanValue = new byte[1+lenLen+huffmanLen]; + ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue); + + // Indicate Huffman + buffer.put((byte)0x80); + // Add huffman length + NBitInteger.encode(buffer,7,huffmanLen); + // Encode value + Huffman.encode(buffer,value); + + } + else + _huffmanValue=null; + } + + @Override + public boolean isStatic() + { + return true; + } + + @Override + public byte[] getStaticHuffmanValue() + { + return _huffmanValue; } } diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java index 34edb32281e..a01a0af4e84 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java @@ -19,20 +19,68 @@ package org.eclipse.jetty.hpack; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.hpack.HpackContext.Entry; +import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.io.ByteBufferPool; public class HpackEncoder -{ - private final ByteBufferPool byteBufferPool; +{ + private final ByteBufferPool _byteBufferPool; + private final HpackContext _context; public HpackEncoder(ByteBufferPool byteBufferPool) { - this.byteBufferPool = byteBufferPool; + this(byteBufferPool,4096); + } + + public HpackEncoder(ByteBufferPool byteBufferPool,int maxHeaderTableSize) + { + this._byteBufferPool = byteBufferPool; + _context=new HpackContext(maxHeaderTableSize); } public ByteBufferPool.Lease encode(HttpFields fields) { - return new ByteBufferPool.Lease(byteBufferPool); + return new ByteBufferPool.Lease(_byteBufferPool); } + + + private boolean encode(ByteBuffer buffer, HttpField field) + { + // Is there an entry for the field? + Entry entry = _context.get(field); + + if (entry!=null) + { + // if entry is already in the reference set, then nothing more to do. + if (entry.isInReferenceSet()) + return true; + + // Is this as static field + if (entry.isStatic()) + { + // TODO Policy decision to make! + // Should we add to reference set or just always send as indexed? + // Let's always send as indexed to reduce churn in header table! + // BUGGER! Can't do that. Oh well all the static fields have small values, so + // lets send as literal header, indexed name. + // We don't need never indexed because the cookie fields are name only and we can + // huffman encode the value for the same reason. + + // Add the token + buffer.put((byte)0x00); + // Add the name index + NBitInteger.encode(buffer,4,_context.index(entry)); + // Add the value + buffer.put(entry.getStaticHuffmanValue()); + + } + } + } + + + } diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java index e21fbd00e2f..eb3fd6ab9ae 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java @@ -341,7 +341,7 @@ public class Huffman } - static public String decode(ByteBuffer buffer) throws IOException + static public String decode(ByteBuffer buffer) { StringBuilder out = new StringBuilder(buffer.remaining()*2); int node = 0; diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java index b4e7db529c6..a61c215e3b0 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.nio.ByteBuffer; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; @@ -397,6 +398,13 @@ public class HpackContextTest ctx.addToRefSet(ctx.get(3)); ctx.addToRefSet(ctx.get(1)); ctx.addToRefSet(ctx.get(5)); + + // check isInReferenceSet + assertTrue(ctx.get(1).isInReferenceSet()); + assertFalse(ctx.get(2).isInReferenceSet()); + assertTrue(ctx.get(3).isInReferenceSet()); + assertFalse(ctx.get(4).isInReferenceSet()); + assertTrue(ctx.get(5).isInReferenceSet()); // iterate ref set HashSet fields = new HashSet<>(); @@ -426,6 +434,13 @@ public class HpackContextTest assertTrue(fields.contains(field[0])); assertTrue(fields.contains(field[4])); + // check isInReferenceSet + assertTrue(ctx.get(1).isInReferenceSet()); + assertFalse(ctx.get(2).isInReferenceSet()); + assertFalse(ctx.get(3).isInReferenceSet()); + assertFalse(ctx.get(4).isInReferenceSet()); + assertTrue(ctx.get(5).isInReferenceSet()); + // iterator remove Iterator iter=ctx.iterateReferenceSet(); iter.next(); @@ -445,6 +460,55 @@ public class HpackContextTest } + @Test + public void testRefSetClear() + { + // Only enough space for 5 entries + HpackContext ctx = new HpackContext(38*5); + + HttpField[] field = + { + new HttpField("fo0","b0r"), + new HttpField("fo1","b1r"), + new HttpField("fo2","b2r"), + new HttpField("fo3","b3r"), + new HttpField("fo4","b4r"), + new HttpField("fo5","b5r"), + new HttpField("fo6","b6r"), + new HttpField("fo7","b7r"), + new HttpField("fo8","b8r"), + new HttpField("fo9","b9r"), + new HttpField("foA","bAr"), + }; + Entry[] entry = new Entry[field.length]; + + // Add 5 entries + for (int i=0;i<=4;i++) + entry[i]=ctx.add(field[i]); + + // Add 3 entries to reference set + ctx.clearReferenceSet(); + ctx.addToRefSet(ctx.get(3)); + ctx.addToRefSet(ctx.get(1)); + ctx.addToRefSet(ctx.get(5)); + + // iterate ref set + HashSet fields = new HashSet<>(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(3,fields.size()); + assertTrue(fields.contains(field[0])); + assertTrue(fields.contains(field[2])); + assertTrue(fields.contains(field[4])); + + // Clear set + ctx.clearReferenceSet(); + fields.clear(); + for (Entry e: ctx.getReferenceSet() ) + fields.add(e.getHttpField()); + assertEquals(0,fields.size()); + } + @Test public void testResize() { @@ -598,8 +662,28 @@ public class HpackContextTest assertFalse(fields.contains(field[0])); assertFalse(fields.contains(field[2])); assertTrue(fields.contains(field[4])); - - - + } + + @Test + public void testStaticHuffmanValues() + { + HpackContext ctx = new HpackContext(4096); + for (int i=2;i<=14;i++) + { + Entry entry=ctx.get(i); + assertTrue(entry.isStatic()); + + ByteBuffer buffer = ByteBuffer.wrap(entry.getStaticHuffmanValue()); + int huff = 0xff&buffer.get(); + assertTrue((0x80&huff)==0x80); + + int len = NBitInteger.decode(buffer,7); + + assertEquals(len,buffer.remaining()); + String value = Huffman.decode(buffer); + + assertEquals(entry.getHttpField().getValue(),value); + + } } } From fdf73adf39e2b0845e762a7e5d46d07e3c3fc68d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Sun, 8 Jun 2014 19:55:56 +0200 Subject: [PATCH 026/269] start of encoder --- .../org/eclipse/jetty/hpack/HpackContext.java | 51 +++- .../org/eclipse/jetty/hpack/HpackEncoder.java | 167 ++++++++++- .../eclipse/jetty/hpack/HpackEncoderTest.java | 274 ++++++++++++++++++ 3 files changed, 484 insertions(+), 8 deletions(-) create mode 100644 jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java index c3e28897706..57fc2330eab 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java @@ -232,6 +232,37 @@ public class HpackContext } } + public void unuseReferenceSet() + { + Entry entry = _refSet._refSetNext; + while(entry!=_refSet) + { + entry._used=false; + entry=entry._refSetNext; + } + } + + + public void removedUnusedReferences(ByteBuffer buffer) + { + Entry entry = _refSet._refSetNext; + while(entry!=_refSet) + { + Entry next = entry._refSetNext; + + if (!entry.isUsed()) + { + // encode the reference to remove it + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,index(entry)); + entry.removeFromRefSet(); + } + entry=next; + } + + } + + public Iterator iterateReferenceSet() { return new Iterator() @@ -350,11 +381,11 @@ public class HpackContext /* ------------------------------------------------------------ */ public static class Entry { - int _index; final HttpField _field; + int _index; Entry _refSetNext=this; Entry _refSetPrev=this; - boolean _refSetUsed; + boolean _used; Entry() { @@ -382,7 +413,8 @@ public class HpackContext throw new IllegalStateException("evicted"); if (_refSetNext!=this) return; - + + _used=true; _refSetNext=ctx._refSet; _refSetPrev=ctx._refSet._refSetPrev; ctx._refSet._refSetPrev._refSetNext=this; @@ -402,6 +434,7 @@ public class HpackContext _refSetPrev._refSetNext=_refSetNext; _refSetNext=this; _refSetPrev=this; + _used=false; } } @@ -429,6 +462,18 @@ public class HpackContext { return String.format("{%s,%d,%s,%x}",isStatic()?"S":"D",_index,_field,hashCode()); } + + public void used() + { + _used=true; + } + + public boolean isUsed() + { + return _used; + } + + } public static class StaticEntry extends Entry diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java index a01a0af4e84..ada2cbc8eef 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java @@ -20,16 +20,49 @@ package org.eclipse.jetty.hpack; import java.nio.ByteBuffer; +import java.util.EnumSet; import org.eclipse.jetty.hpack.HpackContext.Entry; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.io.ByteBufferPool; public class HpackEncoder { + private final static EnumSet __NEVER_INDEX = + EnumSet.of(HttpHeader.SET_COOKIE, + HttpHeader.SET_COOKIE2); + + private final static EnumSet __DO_NOT_HUFFMAN = + EnumSet.of(HttpHeader.COOKIE, + HttpHeader.SET_COOKIE, + HttpHeader.SET_COOKIE2, + HttpHeader.AUTHORIZATION, + HttpHeader.CONTENT_MD5, + HttpHeader.PROXY_AUTHENTICATE, + HttpHeader.PROXY_AUTHORIZATION); + + private final static EnumSet __USE_REFERENCE_SET = + EnumSet.of(HttpHeader.ACCEPT, + HttpHeader.ACCEPT_CHARSET, + HttpHeader.ACCEPT_ENCODING, + HttpHeader.ACCEPT_LANGUAGE, + HttpHeader.ACCEPT_RANGES, + HttpHeader.ALLOW, + HttpHeader.AUTHORIZATION, + HttpHeader.CACHE_CONTROL, + HttpHeader.CONTENT_LANGUAGE, + HttpHeader.COOKIE, + HttpHeader.DATE, + HttpHeader.HOST, + HttpHeader.SERVER, + HttpHeader.SERVLET_ENGINE, + HttpHeader.USER_AGENT); + private final ByteBufferPool _byteBufferPool; private final HpackContext _context; + public HpackEncoder(ByteBufferPool byteBufferPool) { @@ -41,15 +74,38 @@ public class HpackEncoder this._byteBufferPool = byteBufferPool; _context=new HpackContext(maxHeaderTableSize); } + + public HpackContext getContext() + { + return _context; + } + /* public ByteBufferPool.Lease encode(HttpFields fields) { return new ByteBufferPool.Lease(_byteBufferPool); } - - - private boolean encode(ByteBuffer buffer, HttpField field) + */ + + public void encode(ByteBuffer buffer, HttpFields fields) { + // Clear the used bits + _context.unuseReferenceSet(); + + // Add all the known fields + for (HttpField field : fields) + { + encode(buffer,field); + } + + _context.removedUnusedReferences(buffer); + } + + private void encode(ByteBuffer buffer, HttpField field) + { + // TODO currently we do not check if there is enough space, so we will always + // return true or fail nastily. + // Is there an entry for the field? Entry entry = _context.get(field); @@ -57,12 +113,15 @@ public class HpackEncoder { // if entry is already in the reference set, then nothing more to do. if (entry.isInReferenceSet()) - return true; + { + entry.used(); + return; + } // Is this as static field if (entry.isStatic()) { - // TODO Policy decision to make! + // TODO Strategy decision to make! // Should we add to reference set or just always send as indexed? // Let's always send as indexed to reduce churn in header table! // BUGGER! Can't do that. Oh well all the static fields have small values, so @@ -77,9 +136,107 @@ public class HpackEncoder // Add the value buffer.put(entry.getStaticHuffmanValue()); + return; + } + + // So we can add the entry to the reference Set and emit the index; + _context.addToRefSet(entry); + int index=_context.index(entry); + + // TODO pregenerate indexes? + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,index); + return; + } + + + // Must be a new entry, so we will have to send literally. + // TODO Strategy decision to make! + // What fields will we put in the reference set and what fields will we huffman encode? + + // Let's make these decisions by lookup of known fields + HttpHeader header = field.getHeader(); + final boolean never_index; + final boolean huffman; + final boolean reference; + final int name_bits; + final byte mask; + if (header==null) + { + never_index=false; + huffman=true; + reference=true; + name_bits = 6; + mask=(byte)0x40; + } + else if (__USE_REFERENCE_SET.contains(header)) + { + reference=true; + never_index=false; + huffman=__DO_NOT_HUFFMAN.contains(header); + name_bits = 6; + mask=(byte)0x40; + } + else + { + reference=false; + never_index=__NEVER_INDEX.contains(header); + huffman=__DO_NOT_HUFFMAN.contains(header); + name_bits = 4; + mask=never_index?(byte)0x01:(byte)0x00; + } + + + // Add the mask bits + buffer.put(mask); + + // Look for a name Index + Entry name_entry = _context.get(field.getName()); + if (name_entry!=null) + NBitInteger.encode(buffer,name_bits,_context.index(name_entry)); + else + { + // Encode the name always with huffman + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,Huffman.octetsNeeded(field.getName())); + Huffman.encode(buffer,field.getName()); + } + + // Add the literal value + String value=field.getValue(); + if (huffman) + { + // huffman literal value + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,Huffman.octetsNeeded(value)); + Huffman.encode(buffer,field.getValue()); + } + else + { + // add literal assuming iso_8859_1 + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,value.length()); + for (int i=0;i127) + throw new IllegalArgumentException(); + buffer.put((byte)c); } } + + // If we want the field referenced, then we add it to our + // table and reference set. + if (reference) + { + Entry new_entry=_context.add(field); + if (new_entry!=null) + _context.addToRefSet(new_entry); + } + + return; } + diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java new file mode 100644 index 00000000000..08453add37f --- /dev/null +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java @@ -0,0 +1,274 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + + +import static org.junit.Assert.assertThat; + +import java.nio.ByteBuffer; +import java.util.HashSet; + +import org.eclipse.jetty.hpack.HpackContext.Entry; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.util.BufferUtil; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + + +/* ------------------------------------------------------------ */ +/** + */ +public class HpackEncoderTest +{ + @Test + public void testUnknownFieldsContextManagement() + { + HpackEncoder encoder = new HpackEncoder(null,38*5); + HttpFields fields = new HttpFields(); + + + HttpField[] field = + { + new HttpField("fo0","b0r"), + new HttpField("fo1","b1r"), + new HttpField("fo2","b2r"), + new HttpField("fo3","b3r"), + new HttpField("fo4","b4r"), + new HttpField("fo5","b5r"), + new HttpField("fo6","b6r"), + new HttpField("fo7","b7r"), + new HttpField("fo8","b8r"), + new HttpField("fo9","b9r"), + new HttpField("foA","bAr"), + }; + + // Add 4 entries + for (int i=0;i<=3;i++) + fields.add(field[i]); + + // encode them + ByteBuffer buffer = BufferUtil.allocate(4096); + int pos = BufferUtil.flipToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,pos); + + // something was encoded! + assertThat(buffer.remaining(),Matchers.greaterThan(0)); + + // All are in the header table + Assert.assertEquals(4,encoder.getContext().size()); + + // All are in the reference set + HashSet refSet = new HashSet<>(); + for (Entry entry : encoder.getContext().getReferenceSet()) + refSet.add(entry.getHttpField()); + Assert.assertEquals(4,refSet.size()); + for (int i=0;i<=3;i++) + Assert.assertTrue(refSet.contains(field[i])); + + // encode exact same fields again! + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,0); + + // nothing should be encoded! + assertThat(buffer.remaining(),Matchers.is(0)); + + // All are in the header table + Assert.assertEquals(4,encoder.getContext().size()); + + // All are in the reference set + refSet.clear(); + for (Entry entry : encoder.getContext().getReferenceSet()) + refSet.add(entry.getHttpField()); + Assert.assertEquals(4,refSet.size()); + for (int i=0;i<=3;i++) + Assert.assertTrue(refSet.contains(field[i])); + + // Add 4 more fields + for (int i=4;i<=7;i++) + fields.add(field[i]); + + // encode + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,0); + + // something was encoded! + assertThat(buffer.remaining(),Matchers.greaterThan(0)); + + // max header table size reached + Assert.assertEquals(5,encoder.getContext().size()); + + // last 5 in reference set + refSet.clear(); + for (Entry entry : encoder.getContext().getReferenceSet()) + refSet.add(entry.getHttpField()); + Assert.assertEquals(5,refSet.size()); + for (int i=3;i<=7;i++) + Assert.assertTrue(refSet.contains(field[i])); + + + // remove some fields + for (int i=0;i<=7;i+=2) + fields.remove(field[i].getName()); + + // encode + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,0); + + // something was encoded! + assertThat(buffer.remaining(),Matchers.greaterThan(0)); + + // max header table size reached + Assert.assertEquals(5,encoder.getContext().size()); + + // last 5 in reference set + refSet.clear(); + for (Entry entry : encoder.getContext().getReferenceSet()) + refSet.add(entry.getHttpField()); + Assert.assertEquals(4,refSet.size()); + for (int i=0;i<=7;i++) + { + if (i%2==1) + Assert.assertTrue(refSet.contains(field[i])); + else + Assert.assertFalse(refSet.contains(field[i])); + } + + // remove another fields + fields.remove(field[1].getName()); + + // encode + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,0); + + // something was encoded! + assertThat(buffer.remaining(),Matchers.greaterThan(0)); + + // max header table size reached + Assert.assertEquals(5,encoder.getContext().size()); + + // last 5 in reference set + refSet.clear(); + for (Entry entry : encoder.getContext().getReferenceSet()) + refSet.add(entry.getHttpField()); + Assert.assertEquals(3,refSet.size()); + for (int i=2;i<=7;i++) + { + if (i%2==1) + Assert.assertTrue(refSet.contains(field[i])); + else + Assert.assertFalse(refSet.contains(field[i])); + } + + // re add the field + + fields.add(field[1]); + + // encode + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,0); + + // something was encoded! + assertThat(buffer.remaining(),Matchers.greaterThan(0)); + + // max header table size reached + Assert.assertEquals(5,encoder.getContext().size()); + + // last 5 in reference set + refSet.clear(); + for (Entry entry : encoder.getContext().getReferenceSet()) + refSet.add(entry.getHttpField()); + Assert.assertEquals(4,refSet.size()); + for (int i=0;i<=7;i++) + { + if (i%2==1) + Assert.assertTrue(refSet.contains(field[i])); + else + Assert.assertFalse(refSet.contains(field[i])); + } + } + + @Test + public void testDoNotReferenceStatics() + { + HpackEncoder encoder = new HpackEncoder(null,38*5); + ByteBuffer buffer = BufferUtil.allocate(4096); + + HttpFields fields = new HttpFields(); + fields.put(":method","POST"); + + // encode + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,0); + + // something was encoded! + assertThat(buffer.remaining(),Matchers.greaterThan(0)); + + // empty header table + Assert.assertEquals(0,encoder.getContext().size()); + } + + @Test + public void testNeverIndexSetCookie() + { + HpackEncoder encoder = new HpackEncoder(null,38*5); + ByteBuffer buffer = BufferUtil.allocate(4096); + + HttpFields fields = new HttpFields(); + fields.put("set-cookie","some cookie value"); + + // encode + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,0); + + // something was encoded! + assertThat(buffer.remaining(),Matchers.greaterThan(0)); + + // empty header table + Assert.assertEquals(0,encoder.getContext().size()); + + + // encode again + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,fields); + BufferUtil.flipToFlush(buffer,0); + + // something was encoded! + assertThat(buffer.remaining(),Matchers.greaterThan(0)); + + // empty header table + Assert.assertEquals(0,encoder.getContext().size()); + + } + + + + + +} From d7fbd89a75b915cb62154f327d3b6b0bd6ba2fcc Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 9 Jun 2014 01:11:04 +0200 Subject: [PATCH 027/269] working decoder that can handle D3 and D4 examples from draft --- .../org/eclipse/jetty/hpack/HpackContext.java | 31 ++-- .../org/eclipse/jetty/hpack/HpackDecoder.java | 132 +++++++++++++- .../org/eclipse/jetty/hpack/HpackEncoder.java | 3 - .../java/org/eclipse/jetty/hpack/Huffman.java | 12 +- .../org/eclipse/jetty/hpack/NBitInteger.java | 10 +- .../eclipse/jetty/hpack/HpackDecoderTest.java | 172 ++++++++++++++++++ .../org/eclipse/jetty/util/BufferUtil.java | 2 +- 7 files changed, 333 insertions(+), 29 deletions(-) create mode 100644 jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java index 57fc2330eab..3fb1091bc71 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; +import org.eclipse.jetty.hpack.HpackDecoder.Listener; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.ArrayTrie; @@ -232,16 +233,6 @@ public class HpackContext } } - public void unuseReferenceSet() - { - Entry entry = _refSet._refSetNext; - while(entry!=_refSet) - { - entry._used=false; - entry=entry._refSetNext; - } - } - public void removedUnusedReferences(ByteBuffer buffer) { @@ -250,7 +241,9 @@ public class HpackContext { Entry next = entry._refSetNext; - if (!entry.isUsed()) + if (entry.isUsed()) + entry._used=false; + else { // encode the reference to remove it buffer.put((byte)0x80); @@ -259,7 +252,20 @@ public class HpackContext } entry=next; } - + } + + public void emitUnusedReferences(Listener listener) + { + Entry entry = _refSet._refSetNext; + while(entry!=_refSet) + { + if (entry.isUsed()) + entry._used=false; + else + listener.emit(entry.getHttpField()); + + entry=entry._refSetNext; + } } @@ -517,4 +523,5 @@ public class HpackContext + } diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java index cd2fe308303..8670793d5c7 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java @@ -21,7 +21,9 @@ package org.eclipse.jetty.hpack; import java.nio.ByteBuffer; +import org.eclipse.jetty.hpack.HpackContext.Entry; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpHeader; /* ------------------------------------------------------------ */ @@ -36,14 +38,136 @@ public class HpackDecoder void endHeaders(); } - public HpackDecoder(Listener listenr) + private final HpackContext _context; + private final Listener _listener; + + public HpackDecoder(Listener listener) { - + this(listener,4096); } - public void parse(ByteBuffer buffer) + public HpackDecoder(Listener listener,int maxHeaderTableSize) { - + _listener=listener; + _context=new HpackContext(maxHeaderTableSize); } + + + public void decode(ByteBuffer buffer) + { + while(buffer.hasRemaining()) + { + byte b = buffer.get(); + if (b<0) + { + // indexed + int index = NBitInteger.decode(buffer,7); + Entry entry=_context.get(index); + if (entry.isInReferenceSet()) + _context.get(index).removeFromRefSet(); + else if (entry.isStatic()) + { + // emit field + _listener.emit(entry.getHttpField()); + + // copy and add to reference set if there is room + Entry new_entry = _context.add(entry.getHttpField()); + if (new_entry!=null) + _context.addToRefSet(new_entry); + } + else + { + // emit + _listener.emit(entry.getHttpField()); + // add to reference set + _context.addToRefSet(entry); + } + } + else + { + // look at the first nibble in detail + int f=(b&0xF0)>>4; + String name; + HttpHeader header; + String value; + + if (f<=1 || f>=4) + { + // literal + boolean indexed=f>=4; + int bits=indexed?6:4; + + // decode the name + int name_index=NBitInteger.decode(buffer,bits); + if (name_index>0) + { + Entry name_entry=_context.get(name_index); + name=name_entry.getHttpField().getName(); + header=name_entry.getHttpField().getHeader(); + } + else + { + boolean huffman = (buffer.get()&0x80)==0x80; + int length = NBitInteger.decode(buffer,7); + if (huffman) + name=Huffman.decode(buffer,length); + else + name=toASCIIString(buffer,length); + header=HttpHeader.CACHE.get(name); + } + + // decode the value + boolean huffman = (buffer.get()&0x80)==0x80; + int length = NBitInteger.decode(buffer,7); + if (huffman) + value=Huffman.decode(buffer,length); + else + value=toASCIIString(buffer,length); + + // Make the new field + HttpField field = new HttpField(header,name,value); + + // emit the field + _listener.emit(field); + + // if indexed + if (indexed) + { + // add to header table + Entry new_entry=_context.add(field); + // and to ref set if there was room in header table + if (new_entry!=null) + _context.addToRefSet(new_entry); + } + } + else if (f==2) + { + // change table size + int size = NBitInteger.decode(buffer,4); + _context.resize(size); + } + else if (f==3) + { + // clear reference set + _context.clearReferenceSet(); + } + } + } + + _context.emitUnusedReferences(_listener); + _listener.endHeaders(); + } + + public static String toASCIIString(ByteBuffer buffer,int length) + { + StringBuilder builder = new StringBuilder(length); + int start=buffer.arrayOffset()+buffer.position(); + int end=start+length; + buffer.position(end); + byte[] array=buffer.array(); + for (int i=start;i>> (8 - n); - int i=buf.get(buf.position()-1)&nbits; + int i=buffer.get(buffer.position()-1)&nbits; if (i == nbits) { @@ -140,7 +140,7 @@ public class NBitInteger int b; do { - b = 0xff&buf.get(); + b = 0xff&buffer.get(); i = i + (b&127) * m; m = m*128; } diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java new file mode 100644 index 00000000000..26630cccda2 --- /dev/null +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java @@ -0,0 +1,172 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + +import static org.junit.Assert.*; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.hpack.HpackDecoder.Listener; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.util.TypeUtil; +import org.junit.Assert; +import org.junit.Test; + + +/* ------------------------------------------------------------ */ +/** + */ +public class HpackDecoderTest +{ + + @Test + public void testDecodeD_3() + { + final HttpFields fields = new HttpFields(); + Listener listener = new Listener() + { + + @Override + public void endHeaders() + { + System.err.println("==="); + } + + @Override + public void emit(HttpField field) + { + System.err.println(field); + fields.add(field); + } + }; + + HpackDecoder decoder = new HpackDecoder(listener); + + + // First request + String encoded="828786440f7777772e6578616d706c652e636f6d"; + ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + + decoder.decode(buffer); + + assertEquals(4,fields.size()); + assertEquals("GET",fields.get(":method")); + assertEquals("http",fields.get(":scheme")); + assertEquals("/",fields.get(":path")); + assertEquals("www.example.com",fields.get(":authority")); + + + // Second request + fields.clear(); + encoded="5c086e6f2d6361636865"; + buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + + decoder.decode(buffer); + + assertEquals(5,fields.size()); + assertEquals("GET",fields.get(":method")); + assertEquals("http",fields.get(":scheme")); + assertEquals("/",fields.get(":path")); + assertEquals("www.example.com",fields.get(":authority")); + assertEquals("no-cache",fields.get("cache-control")); + + // Third request + fields.clear(); + encoded="30858c8b84400a637573746f6d2d6b65790c637573746f6d2d76616c7565"; + buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + + decoder.decode(buffer); + + assertEquals(5,fields.size()); + assertEquals("GET",fields.get(":method")); + assertEquals("https",fields.get(":scheme")); + assertEquals("/index.html",fields.get(":path")); + assertEquals("www.example.com",fields.get(":authority")); + assertEquals("custom-value",fields.get("custom-key")); + } + + @Test + public void testDecodeD_4() + { + final HttpFields fields = new HttpFields(); + Listener listener = new Listener() + { + + @Override + public void endHeaders() + { + System.err.println("==="); + } + + @Override + public void emit(HttpField field) + { + System.err.println(field); + fields.add(field); + } + }; + + HpackDecoder decoder = new HpackDecoder(listener); + + + // First request + String encoded="828786448ce7cf9bebe89b6fb16fa9b6ff"; + ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + + decoder.decode(buffer); + + assertEquals(4,fields.size()); + assertEquals("GET",fields.get(":method")); + assertEquals("http",fields.get(":scheme")); + assertEquals("/",fields.get(":path")); + assertEquals("www.example.com",fields.get(":authority")); + + + // Second request + fields.clear(); + encoded="5c86b9b9949556bf"; + buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + + decoder.decode(buffer); + + assertEquals(5,fields.size()); + assertEquals("GET",fields.get(":method")); + assertEquals("http",fields.get(":scheme")); + assertEquals("/",fields.get(":path")); + assertEquals("www.example.com",fields.get(":authority")); + assertEquals("no-cache",fields.get("cache-control")); + + // Third request + fields.clear(); + encoded="30858c8b844088571c5cdb737b2faf89571c5cdb73724d9c57"; + buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + + decoder.decode(buffer); + + assertEquals(5,fields.size()); + assertEquals("GET",fields.get(":method")); + assertEquals("https",fields.get(":scheme")); + assertEquals("/index.html",fields.get(":path")); + assertEquals("www.example.com",fields.get(":authority")); + assertEquals("custom-value",fields.get("custom-key")); + } + +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java index bd7cb06ecd1..1b09d6e04c5 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java @@ -518,7 +518,7 @@ public class BufferUtil } /* ------------------------------------------------------------ */ - /** Convert a partial buffer to an ISO-8859-1 String + /** Convert a partial buffer to a String * @param buffer The buffer to convert in flush mode. The buffer is unchanged * @param charset The {@link Charset} to use to convert the bytes * @return The buffer as a string. From e81e01719f5ee10cf3281d906b4b3c2c92b8db69 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 9 Jun 2014 10:05:19 +0200 Subject: [PATCH 028/269] use buffer leases --- .../java/org/eclipse/jetty/hpack/HpackEncoder.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java index 86ca63b6e7e..3009ee45cbb 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.ByteBufferPool.Lease; public class HpackEncoder { @@ -80,12 +81,15 @@ public class HpackEncoder return _context; } - /* public ByteBufferPool.Lease encode(HttpFields fields) { - return new ByteBufferPool.Lease(_byteBufferPool); + Lease lease=new ByteBufferPool.Lease(_byteBufferPool); + ByteBuffer buffer = _byteBufferPool.acquire(8*1024,false); // TODO make configurable + lease.add(buffer,true); + // TODO handle multiple buffers if large size configured. + encode(buffer,fields); + return lease; } - */ public void encode(ByteBuffer buffer, HttpFields fields) { From 36081dbcbf64243f1c2098067290e490dc3ec656 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 9 Jun 2014 13:01:15 +0200 Subject: [PATCH 029/269] reworked for metadata --- .../java/org/eclipse/jetty/hpack/Field.java | 94 ----------- .../org/eclipse/jetty/hpack/HpackContext.java | 67 ++++++-- .../org/eclipse/jetty/hpack/HpackDecoder.java | 28 ++-- .../org/eclipse/jetty/hpack/HpackEncoder.java | 56 +++++-- .../org/eclipse/jetty/hpack/MetaData.java | 153 ++++++++++++++++++ .../eclipse/jetty/hpack/MetaDataBuilder.java | 129 +++++++++++++++ .../eclipse/jetty/hpack/HpackDecoderTest.java | 151 ++++++++--------- .../eclipse/jetty/hpack/HpackEncoderTest.java | 24 +-- .../org/eclipse/jetty/hpack/HpackTest.java | 35 ++++ .../org/eclipse/jetty/io/ByteBufferPool.java | 8 + 10 files changed, 509 insertions(+), 236 deletions(-) delete mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java create mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaData.java create mode 100644 jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaDataBuilder.java create mode 100644 jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackTest.java diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java deleted file mode 100644 index 259e55a79c4..00000000000 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Field.java +++ /dev/null @@ -1,94 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.hpack; - -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpHeader; - -/* ------------------------------------------------------------ */ -/** - */ -public class Field extends HttpField -{ - // final ByteBuffer _nameLiteral; - // final ByteBuffer _nameHuffman; - private final NameKey _nameKey=new NameKey(); - - public Field(String name,String value) - { - super(HttpHeader.CACHE.get(name),name,value); - - // Generate a non huffman literal field - /* - _nameLiteral=BufferUtil.allocate(1+NBitInteger.octectsNeeded(7,name.length())+name.length()); - BufferUtil.flipToFill(_nameLiteral); - _nameLiteral.put((byte)0x00); - NBitInteger.encode(_nameLiteral,7,name.length()); - for (int i=0;i126) - throw new IllegalArgumentException(); - _nameLiteral.array()[_nameLiteral.position()+i]=(byte)c; - } - _nameLiteral.position(_nameLiteral.limit()); - BufferUtil.flipToFlush(_nameLiteral,0); - - // Generate a huffman literal field - int h=Huffman.octetsNeeded(name); - _nameHuffman=BufferUtil.allocate(1+NBitInteger.octectsNeeded(7,h)+h); - BufferUtil.flipToFill(_nameHuffman); - _nameHuffman.put((byte)0x80); - NBitInteger.encode(_nameHuffman,7,name.length()); - for (int i=0;i126) - throw new IllegalArgumentException(); - _nameHuffman.array()[_nameHuffman.position()+i]=(byte)c; - } - _nameHuffman.position(_nameHuffman.limit()); - BufferUtil.flipToFlush(_nameHuffman,0); - */ - } - - public NameKey getNameKey() - { - return _nameKey; - } - - public class NameKey - { - - public Field getField() - { - return Field.this; - } - - @Override - public String toString() - { - return getName(); - } - }; -} - - - diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java index 3fb1091bc71..00626d5d22c 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java @@ -26,8 +26,9 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; -import org.eclipse.jetty.hpack.HpackDecoder.Listener; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.StringUtil; @@ -111,7 +112,37 @@ public class HpackContext Set added = new HashSet<>(); for (int i=1;i0) { int huffmanLen = Huffman.octetsNeeded(value); @@ -501,8 +531,7 @@ public class HpackContext // Add huffman length NBitInteger.encode(buffer,7,huffmanLen); // Encode value - Huffman.encode(buffer,value); - + Huffman.encode(buffer,value); } else _huffmanValue=null; @@ -521,7 +550,23 @@ public class HpackContext } } + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + public static class StaticValueHttpField extends HttpField + { + private final Object _value; + public StaticValueHttpField(String name, String valueString, Object value) + { + super(name,valueString); + _value=value; + } + public Object getStaticValue() + { + return _value; + } + } } diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java index 8670793d5c7..60bfa320bea 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java @@ -32,30 +32,24 @@ import org.eclipse.jetty.http.HttpHeader; */ public class HpackDecoder { - public interface Listener - { - void emit(HttpField field); - void endHeaders(); - } private final HpackContext _context; - private final Listener _listener; + private final MetaDataBuilder _builder = new MetaDataBuilder(); - public HpackDecoder(Listener listener) + public HpackDecoder() { - this(listener,4096); + this(4096); } - public HpackDecoder(Listener listener,int maxHeaderTableSize) + public HpackDecoder(int maxHeaderTableSize) { - _listener=listener; _context=new HpackContext(maxHeaderTableSize); } - - public void decode(ByteBuffer buffer) + public MetaData decode(ByteBuffer buffer) { + while(buffer.hasRemaining()) { byte b = buffer.get(); @@ -69,7 +63,7 @@ public class HpackDecoder else if (entry.isStatic()) { // emit field - _listener.emit(entry.getHttpField()); + _builder.emit(entry.getHttpField()); // copy and add to reference set if there is room Entry new_entry = _context.add(entry.getHttpField()); @@ -79,7 +73,7 @@ public class HpackDecoder else { // emit - _listener.emit(entry.getHttpField()); + _builder.emit(entry.getHttpField()); // add to reference set _context.addToRefSet(entry); } @@ -129,7 +123,7 @@ public class HpackDecoder HttpField field = new HttpField(header,name,value); // emit the field - _listener.emit(field); + _builder.emit(field); // if indexed if (indexed) @@ -155,8 +149,8 @@ public class HpackDecoder } } - _context.emitUnusedReferences(_listener); - _listener.endHeaders(); + _context.emitUnusedReferences(_builder); + return _builder.build(); } public static String toASCIIString(ByteBuffer buffer,int length) diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java index 3009ee45cbb..38db9ce7c07 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java @@ -26,11 +26,14 @@ import org.eclipse.jetty.hpack.HpackContext.Entry; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool.Lease; public class HpackEncoder { + private final static HttpField[] __status= new HttpField[599]; + private final static EnumSet __NEVER_INDEX = EnumSet.of(HttpHeader.SET_COOKIE, HttpHeader.SET_COOKIE2); @@ -61,18 +64,22 @@ public class HpackEncoder HttpHeader.SERVLET_ENGINE, HttpHeader.USER_AGENT); - private final ByteBufferPool _byteBufferPool; + static + { + for (HttpStatus.Code code : HttpStatus.Code.values()) + __status[code.getCode()]=new HttpField(":status",Integer.toString(code.getCode())); + } + private final HpackContext _context; - public HpackEncoder(ByteBufferPool byteBufferPool) + public HpackEncoder() { - this(byteBufferPool,4096); + this(4096); } - public HpackEncoder(ByteBufferPool byteBufferPool,int maxHeaderTableSize) + public HpackEncoder(int maxHeaderTableSize) { - this._byteBufferPool = byteBufferPool; _context=new HpackContext(maxHeaderTableSize); } @@ -81,20 +88,41 @@ public class HpackEncoder return _context; } - public ByteBufferPool.Lease encode(HttpFields fields) + public void encode(MetaData metadata,Lease lease) { - Lease lease=new ByteBufferPool.Lease(_byteBufferPool); - ByteBuffer buffer = _byteBufferPool.acquire(8*1024,false); // TODO make configurable - lease.add(buffer,true); + ByteBuffer buffer = lease.acquire(8*1024,false); // TODO make size configurable + // TODO handle multiple buffers if large size configured. - encode(buffer,fields); - return lease; + encode(buffer,metadata); } - public void encode(ByteBuffer buffer, HttpFields fields) + public void encode(ByteBuffer buffer, MetaData metadata) { - // Add all the known fields - for (HttpField field : fields) + // Add Request/response meta fields + + if (metadata.isRequest()) + { + MetaData.Request request = (MetaData.Request)metadata; + + // TODO optimise these to avoid HttpField creation + encode(buffer,new HttpField(":scheme",request.getScheme().asString())); + encode(buffer,new HttpField(":method",request.getMethodString())); + encode(buffer,new HttpField(":authority",request.getAuthority())); // TODO look for host header? + encode(buffer,new HttpField(":path",request.getPath())); + + } + else if (metadata.isResponse()) + { + MetaData.Response response = (MetaData.Response)metadata; + int code=response.getStatus(); + HttpField status = code<__status.length?__status[code]:null; + if (status==null) + status=new HttpField(":status",Integer.toString(code)); + encode(buffer,status); + } + + // Add all the other fields + for (HttpField field : metadata) { encode(buffer,field); } diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaData.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaData.java new file mode 100644 index 00000000000..c07a7dda7ed --- /dev/null +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaData.java @@ -0,0 +1,153 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + +import java.util.Iterator; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; + + +/* ------------------------------------------------------------ */ +/** + */ +public class MetaData implements Iterable +{ + private final Iterable _fields; + + public MetaData(Iterable fields) + { + _fields=fields; + } + + public boolean isRequest() + { + return false; + } + + public boolean isResponse() + { + return false; + } + + @Override + public Iterator iterator() + { + return _fields.iterator(); + } + + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + public static class Request extends MetaData + { + private final HttpMethod _method; + private final String _methodString; + private final HttpScheme _scheme; + private final String _authority; + private final String _path; + + public Request(HttpScheme scheme, HttpMethod method, String methodString, String authority, String path, Iterable fields) + { + super(fields); + _authority=authority; + _method=method; + _methodString=methodString; + _path=path; + _scheme=scheme; + } + + @Override + public boolean isRequest() + { + return true; + } + + @Override + public boolean isResponse() + { + return false; + } + + public HttpMethod getMethod() + { + return _method; + } + + public String getMethodString() + { + return _methodString; + } + + public HttpScheme getScheme() + { + return _scheme; + } + + public String getAuthority() + { + return _authority; + } + + public String getPath() + { + return _path; + } + } + + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + public static class Response extends MetaData + { + private final int _status; + + public Response(int status, HttpFields fields) + { + super(fields); + _status=status; + } + + public Response(int status, Iterable fields) + { + super(fields); + _status=status; + } + + @Override + public boolean isRequest() + { + return false; + } + + @Override + public boolean isResponse() + { + return true; + } + + public int getStatus() + { + return _status; + } + } +} diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaDataBuilder.java b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaDataBuilder.java new file mode 100644 index 00000000000..8d54af096c7 --- /dev/null +++ b/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaDataBuilder.java @@ -0,0 +1,129 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; + +/* -------------------------------------------------------- */ +/* -------------------------------------------------------- */ +/* -------------------------------------------------------- */ +public class MetaDataBuilder +{ + private int _status; + private HttpMethod _method; + private String _methodString; + private HttpScheme _scheme; + private String _authority; + private String _path; + + List _fields = new ArrayList<>(); + + public void emit(HttpField field) + { + if (field instanceof HpackContext.StaticValueHttpField) + { + HpackContext.StaticValueHttpField value = (HpackContext.StaticValueHttpField)field; + switch(field.getName()) + { + case ":status": + _status=(Integer)value.getStaticValue(); + break; + + case ":method": + _method=(HttpMethod)value.getStaticValue(); + _methodString=_method.asString(); + break; + + case ":scheme": + _scheme = (HttpScheme)value.getStaticValue(); + break; + + case ":authority": + _authority=field.getValue(); + break; + + case ":path": + _path=field.getValue(); + break; + + default: + if (field.getName().charAt(0)!=':') + _fields.add(field); + } + } + else + { + + switch(field.getName()) + { + case ":status": + _status=Integer.parseInt(field.getValue()); + break; + + case ":method": + _methodString=field.getValue(); + _method=HttpMethod.CACHE.get(_methodString); + break; + + case ":scheme": + _scheme = HttpScheme.valueOf(field.getValue()); + break; + + case ":authority": + _authority=field.getValue(); + break; + + case ":path": + _path=field.getValue(); + break; + + default: + if (field.getName().charAt(0)!=':') + _fields.add(field); + } + } + } + + public MetaData build() + { + try + { + if (_method!=null) + return new MetaData.Request(_scheme,_method,_methodString,_authority,_path,new ArrayList<>(_fields)); + if (_status!=0) + return new MetaData.Response(_status,new ArrayList<>(_fields)); + return new MetaData(new ArrayList<>(_fields)); + } + finally + { + _status=0; + _method=null; + _scheme=null; + _authority=null; + _path=null; + _fields.clear(); + } + } +} \ No newline at end of file diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java index 26630cccda2..dd490f49162 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java @@ -22,12 +22,12 @@ package org.eclipse.jetty.hpack; import static org.junit.Assert.*; import java.nio.ByteBuffer; +import java.util.Iterator; -import org.eclipse.jetty.hpack.HpackDecoder.Listener; import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.util.TypeUtil; -import org.junit.Assert; import org.junit.Test; @@ -39,134 +39,109 @@ public class HpackDecoderTest @Test public void testDecodeD_3() - { - final HttpFields fields = new HttpFields(); - Listener listener = new Listener() - { - - @Override - public void endHeaders() - { - System.err.println("==="); - } - - @Override - public void emit(HttpField field) - { - System.err.println(field); - fields.add(field); - } - }; - - HpackDecoder decoder = new HpackDecoder(listener); - - + { + HpackDecoder decoder = new HpackDecoder(); + // First request String encoded="828786440f7777772e6578616d706c652e636f6d"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - decoder.decode(buffer); + MetaData.Request request = (MetaData.Request)decoder.decode(buffer); - assertEquals(4,fields.size()); - assertEquals("GET",fields.get(":method")); - assertEquals("http",fields.get(":scheme")); - assertEquals("/",fields.get(":path")); - assertEquals("www.example.com",fields.get(":authority")); + assertEquals(HttpMethod.GET,request.getMethod()); + assertEquals("GET",request.getMethodString()); + assertEquals(HttpScheme.HTTP,request.getScheme()); + assertEquals("/",request.getPath()); + assertEquals("www.example.com",request.getAuthority()); + assertFalse(request.iterator().hasNext()); // Second request - fields.clear(); encoded="5c086e6f2d6361636865"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - decoder.decode(buffer); + request = (MetaData.Request)decoder.decode(buffer); + + assertEquals(HttpMethod.GET,request.getMethod()); + assertEquals("GET",request.getMethodString()); + assertEquals(HttpScheme.HTTP,request.getScheme()); + assertEquals("/",request.getPath()); + assertEquals("www.example.com",request.getAuthority()); + Iterator iterator=request.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); + assertFalse(iterator.hasNext()); - assertEquals(5,fields.size()); - assertEquals("GET",fields.get(":method")); - assertEquals("http",fields.get(":scheme")); - assertEquals("/",fields.get(":path")); - assertEquals("www.example.com",fields.get(":authority")); - assertEquals("no-cache",fields.get("cache-control")); // Third request - fields.clear(); encoded="30858c8b84400a637573746f6d2d6b65790c637573746f6d2d76616c7565"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - decoder.decode(buffer); + request = (MetaData.Request)decoder.decode(buffer); - assertEquals(5,fields.size()); - assertEquals("GET",fields.get(":method")); - assertEquals("https",fields.get(":scheme")); - assertEquals("/index.html",fields.get(":path")); - assertEquals("www.example.com",fields.get(":authority")); - assertEquals("custom-value",fields.get("custom-key")); + assertEquals(HttpMethod.GET,request.getMethod()); + assertEquals("GET",request.getMethodString()); + assertEquals(HttpScheme.HTTPS,request.getScheme()); + assertEquals("/index.html",request.getPath()); + assertEquals("www.example.com",request.getAuthority()); + iterator=request.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); + assertFalse(iterator.hasNext()); } @Test public void testDecodeD_4() { - final HttpFields fields = new HttpFields(); - Listener listener = new Listener() - { - - @Override - public void endHeaders() - { - System.err.println("==="); - } - - @Override - public void emit(HttpField field) - { - System.err.println(field); - fields.add(field); - } - }; - HpackDecoder decoder = new HpackDecoder(listener); + HpackDecoder decoder = new HpackDecoder(); // First request String encoded="828786448ce7cf9bebe89b6fb16fa9b6ff"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - decoder.decode(buffer); + MetaData.Request request = (MetaData.Request)decoder.decode(buffer); - assertEquals(4,fields.size()); - assertEquals("GET",fields.get(":method")); - assertEquals("http",fields.get(":scheme")); - assertEquals("/",fields.get(":path")); - assertEquals("www.example.com",fields.get(":authority")); + assertEquals(HttpMethod.GET,request.getMethod()); + assertEquals("GET",request.getMethodString()); + assertEquals(HttpScheme.HTTP,request.getScheme()); + assertEquals("/",request.getPath()); + assertEquals("www.example.com",request.getAuthority()); + assertFalse(request.iterator().hasNext()); // Second request - fields.clear(); encoded="5c86b9b9949556bf"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - decoder.decode(buffer); - - assertEquals(5,fields.size()); - assertEquals("GET",fields.get(":method")); - assertEquals("http",fields.get(":scheme")); - assertEquals("/",fields.get(":path")); - assertEquals("www.example.com",fields.get(":authority")); - assertEquals("no-cache",fields.get("cache-control")); + request = (MetaData.Request)decoder.decode(buffer); + + assertEquals(HttpMethod.GET,request.getMethod()); + assertEquals("GET",request.getMethodString()); + assertEquals(HttpScheme.HTTP,request.getScheme()); + assertEquals("/",request.getPath()); + assertEquals("www.example.com",request.getAuthority()); + Iterator iterator=request.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); + assertFalse(iterator.hasNext()); // Third request - fields.clear(); encoded="30858c8b844088571c5cdb737b2faf89571c5cdb73724d9c57"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - decoder.decode(buffer); + request = (MetaData.Request)decoder.decode(buffer); - assertEquals(5,fields.size()); - assertEquals("GET",fields.get(":method")); - assertEquals("https",fields.get(":scheme")); - assertEquals("/index.html",fields.get(":path")); - assertEquals("www.example.com",fields.get(":authority")); - assertEquals("custom-value",fields.get("custom-key")); + assertEquals(HttpMethod.GET,request.getMethod()); + assertEquals("GET",request.getMethodString()); + assertEquals(HttpScheme.HTTPS,request.getScheme()); + assertEquals("/index.html",request.getPath()); + assertEquals("www.example.com",request.getAuthority()); + iterator=request.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); + assertFalse(iterator.hasNext()); } } diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java index 08453add37f..eb343b4d00c 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java @@ -42,7 +42,7 @@ public class HpackEncoderTest @Test public void testUnknownFieldsContextManagement() { - HpackEncoder encoder = new HpackEncoder(null,38*5); + HpackEncoder encoder = new HpackEncoder(38*5); HttpFields fields = new HttpFields(); @@ -68,7 +68,7 @@ public class HpackEncoderTest // encode them ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,pos); // something was encoded! @@ -87,7 +87,7 @@ public class HpackEncoderTest // encode exact same fields again! BufferUtil.clearToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,0); // nothing should be encoded! @@ -110,7 +110,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -134,7 +134,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -161,7 +161,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -189,7 +189,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -215,7 +215,7 @@ public class HpackEncoderTest @Test public void testDoNotReferenceStatics() { - HpackEncoder encoder = new HpackEncoder(null,38*5); + HpackEncoder encoder = new HpackEncoder(38*5); ByteBuffer buffer = BufferUtil.allocate(4096); HttpFields fields = new HttpFields(); @@ -223,7 +223,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -236,7 +236,7 @@ public class HpackEncoderTest @Test public void testNeverIndexSetCookie() { - HpackEncoder encoder = new HpackEncoder(null,38*5); + HpackEncoder encoder = new HpackEncoder(38*5); ByteBuffer buffer = BufferUtil.allocate(4096); HttpFields fields = new HttpFields(); @@ -244,7 +244,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -256,7 +256,7 @@ public class HpackEncoderTest // encode again BufferUtil.clearToFill(buffer); - encoder.encode(buffer,fields); + encoder.encode(buffer,new MetaData(fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackTest.java b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackTest.java new file mode 100644 index 00000000000..1c0f77c68b6 --- /dev/null +++ b/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackTest.java @@ -0,0 +1,35 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.hpack; + +import org.eclipse.jetty.http.HttpFields; +import org.junit.Test; + + +public class HpackTest +{ + @Test + public void encodeDecodeTest() + { + HttpFields fields = new HttpFields(); + + + } +} diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index f0153dc2f7a..e4934f6964b 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -64,6 +64,14 @@ public interface ByteBufferPool this.recycles = new ArrayList<>(); } + public ByteBuffer acquire(int capacity,boolean direct) + { + ByteBuffer buffer = byteBufferPool.acquire(capacity,direct); + buffers.add(buffer); + recycles.add(true); + return buffer; + } + public void add(ByteBuffer buffer, boolean recycle) { buffers.add(buffer); From c1247ff6779c78917598a149d36e773702c490d5 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 9 Jun 2014 13:08:54 +0200 Subject: [PATCH 030/269] Reorganized HTTP2 modules. --- jetty-http2/http2-common/pom.xml | 57 +++++++ .../eclipse/jetty/http2/HTTP2Connection.java | 103 +++++++++++++ .../org/eclipse/jetty/http2/HTTP2Session.java | 141 ++++++++++++++++++ .../org/eclipse/jetty/http2/HTTP2Stream.java | 57 +++++++ .../java/org/eclipse/jetty/http2/IStream.java | 26 ++++ .../org/eclipse/jetty/http2/api/Session.java | 91 +++++++++++ .../org/eclipse/jetty/http2/api/Stream.java | 60 ++++++++ .../api/server/ServerSessionListener.java | 34 +++++ .../eclipse/jetty/http2/frames/DataFrame.java | 0 .../org/eclipse/jetty/http2/frames/Flag.java | 0 .../org/eclipse/jetty/http2/frames/Frame.java | 0 .../eclipse/jetty/http2/frames/FrameType.java | 0 .../jetty/http2/frames/GoAwayFrame.java | 0 .../jetty/http2/frames/HeadersFrame.java | 28 +++- .../eclipse/jetty/http2/frames/PingFrame.java | 0 .../jetty/http2/frames/PriorityFrame.java | 0 .../jetty/http2/frames/ResetFrame.java | 0 .../jetty/http2/frames/SettingsFrame.java | 0 .../jetty/http2/frames/WindowUpdateFrame.java | 0 .../jetty/http2/generator/Generator.java | 40 +++-- .../jetty/http2/parser/BodyParser.java | 0 .../jetty/http2/parser/DataBodyParser.java | 0 .../eclipse/jetty/http2/parser/ErrorCode.java | 0 .../jetty/http2/parser/GoAwayBodyParser.java | 0 .../jetty/http2/parser/HeaderBlockParser.java | 83 +++++++++++ .../jetty/http2/parser/HeaderParser.java | 0 .../jetty/http2/parser/HeadersBodyParser.java | 31 ++-- .../eclipse/jetty/http2/parser/Parser.java | 9 +- .../jetty/http2/parser/PingBodyParser.java | 0 .../http2/parser/PriorityBodyParser.java | 0 .../jetty/http2/parser/ResetBodyParser.java | 0 .../http2/parser/SettingsBodyParser.java | 0 .../http2/parser/WindowUpdateBodyParser.java | 0 .../eclipse/jetty/http2/api/UsageTest.java | 60 ++++++++ .../http2/frames/DataGenerateParseTest.java | 4 +- .../http2/frames/GoAwayGenerateParseTest.java | 4 +- .../frames/HeadersGenerateParseTest.java | 0 .../http2/frames/PingGenerateParseTest.java | 4 +- .../frames/PriorityGenerateParseTest.java | 4 +- .../http2/frames/ResetGenerateParseTest.java | 4 +- .../frames/SettingsGenerateParseTest.java | 6 +- .../frames/WindowUpdateGenerateParseTest.java | 4 +- .../http2-hpack}/pom.xml | 37 +---- .../jetty/http2}/hpack/HpackContext.java | 2 +- .../jetty/http2}/hpack/HpackDecoder.java | 4 +- .../jetty/http2}/hpack/HpackEncoder.java | 6 +- .../eclipse/jetty/http2}/hpack/Huffman.java | 3 +- .../eclipse/jetty/http2}/hpack/MetaData.java | 2 +- .../jetty/http2}/hpack/MetaDataBuilder.java | 4 +- .../jetty/http2}/hpack/NBitInteger.java | 2 +- .../jetty/http2}/hpack/HpackContextTest.java | 16 +- .../jetty/http2}/hpack/HpackDecoderTest.java | 16 +- .../jetty/http2}/hpack/HpackEncoderTest.java | 8 +- .../eclipse/jetty/http2}/hpack/HpackTest.java | 2 +- .../jetty/http2}/hpack/HuffmanTest.java | 4 +- .../jetty/http2}/hpack/NBitIntegerTest.java | 6 +- jetty-http2/http2-server/pom.xml | 59 ++++++++ .../server/HTTP2ServerConnectionFactory.java | 109 ++++++++++++++ .../http2/server/HTTP2ServerSession.java | 54 +++++++ .../http2/server/HttpChannelOverHTTP2.java | 53 +++++++ .../http2/server/HttpInputOverHTTP2.java | 48 ++++++ .../http2/server/HttpTransportOverHTTP2.java | 48 ++++++ jetty-http2/pom.xml | 71 ++------- pom.xml | 1 - 64 files changed, 1228 insertions(+), 177 deletions(-) create mode 100644 jetty-http2/http2-common/pom.xml create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/Flag.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/Frame.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java (70%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/generator/Generator.java (91%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java (100%) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java (87%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/Parser.java (95%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java (100%) rename jetty-http2/{ => http2-common}/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java (100%) create mode 100644 jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/api/UsageTest.java rename jetty-http2/{ => http2-common}/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java (97%) rename jetty-http2/{ => http2-common}/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java (95%) rename jetty-http2/{ => http2-common}/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java (100%) rename jetty-http2/{ => http2-common}/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java (95%) rename jetty-http2/{ => http2-common}/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java (95%) rename jetty-http2/{ => http2-common}/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java (95%) rename jetty-http2/{ => http2-common}/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java (95%) rename jetty-http2/{ => http2-common}/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java (95%) rename {jetty-hpack => jetty-http2/http2-hpack}/pom.xml (68%) rename {jetty-hpack/src/main/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2}/hpack/HpackContext.java (99%) rename {jetty-hpack/src/main/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2}/hpack/HpackDecoder.java (98%) rename {jetty-hpack/src/main/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2}/hpack/HpackEncoder.java (98%) rename {jetty-hpack/src/main/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2}/hpack/Huffman.java (99%) rename {jetty-hpack/src/main/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2}/hpack/MetaData.java (98%) rename {jetty-hpack/src/main/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2}/hpack/MetaDataBuilder.java (98%) rename {jetty-hpack/src/main/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2}/hpack/NBitInteger.java (99%) rename {jetty-hpack/src/test/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2}/hpack/HpackContextTest.java (99%) rename {jetty-hpack/src/test/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2}/hpack/HpackDecoderTest.java (93%) rename {jetty-hpack/src/test/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2}/hpack/HpackEncoderTest.java (98%) rename {jetty-hpack/src/test/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2}/hpack/HpackTest.java (96%) rename {jetty-hpack/src/test/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2}/hpack/HuffmanTest.java (98%) rename {jetty-hpack/src/test/java/org/eclipse/jetty => jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2}/hpack/NBitIntegerTest.java (99%) create mode 100644 jetty-http2/http2-server/pom.xml create mode 100644 jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java create mode 100644 jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java create mode 100644 jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java create mode 100644 jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java create mode 100644 jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java diff --git a/jetty-http2/http2-common/pom.xml b/jetty-http2/http2-common/pom.xml new file mode 100644 index 00000000000..0ea64885cb8 --- /dev/null +++ b/jetty-http2/http2-common/pom.xml @@ -0,0 +1,57 @@ + + + + org.eclipse.jetty.http2 + http2-parent + 10.0.0-SNAPSHOT + + + 4.0.0 + http2-common + Jetty :: HTTP2 :: Common + + + + org.eclipse.jetty + http2-hpack + ${project.version} + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + manifest + + + + javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,* + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + + diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java new file mode 100644 index 00000000000..c3243b86c19 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -0,0 +1,103 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.Executor; + +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.AbstractConnection; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class HTTP2Connection extends AbstractConnection +{ + private static final Logger LOG = Log.getLogger(HTTP2Connection.class); + + private final ByteBufferPool byteBufferPool; + private final Parser parser; + private final int bufferSize; + + public HTTP2Connection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, int bufferSize) + { + super(endPoint, executor); + this.byteBufferPool = byteBufferPool; + this.parser = parser; + this.bufferSize = bufferSize; + } + + @Override + public void onOpen() + { + super.onOpen(); + fillInterested(); + } + + @Override + public void onFillable() + { + ByteBuffer buffer = byteBufferPool.acquire(bufferSize, false); + boolean readMore = read(buffer) == 0; + byteBufferPool.release(buffer); + if (readMore) + fillInterested(); + } + + protected int read(ByteBuffer buffer) + { + EndPoint endPoint = getEndPoint(); + while (true) + { + int filled = fill(endPoint, buffer); + if (LOG.isDebugEnabled()) // Avoid boxing of variable 'filled' + LOG.debug("Read {} bytes", filled); + if (filled == 0) + { + return 0; + } + else if (filled < 0) + { + close(); + return -1; + } + else + { + parser.parse(buffer); + } + } + } + + private int fill(EndPoint endPoint, ByteBuffer buffer) + { + try + { + if (endPoint.isInputShutdown()) + return -1; + return endPoint.fill(buffer); + } + catch (IOException x) + { + LOG.debug("Could not read from " + endPoint, x); + return -1; + } + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java new file mode 100644 index 00000000000..d82a8a724de --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -0,0 +1,141 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.GoAwayFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PingFrame; +import org.eclipse.jetty.http2.frames.PriorityFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public abstract class HTTP2Session implements Session, Parser.Listener +{ + private static final Logger LOG = Log.getLogger(HTTP2Session.class); + + private final Listener listener; + + public HTTP2Session(Session.Listener listener) + { + this.listener = listener; + } + + @Override + public boolean onData(DataFrame frame) + { + return false; + } + + @Override + public abstract boolean onHeaders(HeadersFrame frame); + + @Override + public boolean onPriority(PriorityFrame frame) + { + return false; + } + + @Override + public boolean onReset(ResetFrame frame) + { + return false; + } + + @Override + public boolean onSettings(SettingsFrame frame) + { + return false; + } + + @Override + public boolean onPing(PingFrame frame) + { + return false; + } + + @Override + public boolean onGoAway(GoAwayFrame frame) + { + return false; + } + + @Override + public boolean onWindowUpdate(WindowUpdateFrame frame) + { + return false; + } + + @Override + public void onConnectionFailure(int error, String reason) + { + + } + + @Override + public void newStream(HeadersFrame frame, Stream.Listener listener, Promise promise) + { + + } + + @Override + public void settings(SettingsFrame frame, Callback callback) + { + + } + + @Override + public void ping(PingFrame frame, Callback callback) + { + + } + + @Override + public void reset(ResetFrame frame, Callback callback) + { + + } + + @Override + public void close(GoAwayFrame frame, Callback callback) + { + + } + + protected Stream.Listener notifyNewStream(Stream stream, HeadersFrame frame) + { + try + { + return listener.onNewStream(stream, frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return null; + } + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java new file mode 100644 index 00000000000..2447ecf4162 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -0,0 +1,57 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.Callback; + +public class HTTP2Stream implements IStream +{ + @Override + public int getId() + { + return 0; + } + + @Override + public Session getSession() + { + return null; + } + + @Override + public void headers(HeadersFrame frame, Callback callback) + { + + } + + @Override + public void data(DataFrame frame, Callback callback) + { + + } + + @Override + public void setListener(Listener listener) + { + + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java new file mode 100644 index 00000000000..9304f89137e --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -0,0 +1,26 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +import org.eclipse.jetty.http2.api.Stream; + +public interface IStream extends Stream +{ + public void setListener(Listener listener); +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java new file mode 100644 index 00000000000..9d706e3aceb --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java @@ -0,0 +1,91 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.api; + +import org.eclipse.jetty.http2.frames.GoAwayFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PingFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; + +public interface Session +{ + public void newStream(HeadersFrame frame, Stream.Listener listener, Promise promise); + + public void settings(SettingsFrame frame, Callback callback); + + public void ping(PingFrame frame, Callback callback); + + public void reset(ResetFrame frame, Callback callback); + + public void close(GoAwayFrame frame, Callback callback); + + // TODO: getStreams(), remote and local address, etc. see SPDY's Session + + public interface Listener + { + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame); + + public void onSettings(Session session, SettingsFrame frame); + + public void onPing(Session session, PingFrame frame); + + public void onReset(Session session, ResetFrame frame); + + public void onClose(Session session, GoAwayFrame frame); + + public void onFailure(Session session, Throwable failure); + + public static class Adapter implements Session.Listener + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + return null; + } + + @Override + public void onSettings(Session session, SettingsFrame frame) + { + } + + @Override + public void onPing(Session session, PingFrame frame) + { + } + + @Override + public void onReset(Session session, ResetFrame frame) + { + } + + @Override + public void onClose(Session session, GoAwayFrame frame) + { + } + + @Override + public void onFailure(Session session, Throwable failure) + { + } + } + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java new file mode 100644 index 00000000000..2dbc10cee63 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.api; + +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.Callback; + +public interface Stream +{ + public int getId(); + + public Session getSession(); + + public void headers(HeadersFrame frame, Callback callback); + + public void data(DataFrame frame, Callback callback); + + // TODO: see SPDY's Stream + + public interface Listener + { + public void onData(Stream stream, DataFrame frame); + + public void onFailure(Stream stream, Throwable x); + + // TODO: See SPDY's StreamFrameListener + + public static class Adapter implements Listener + { + @Override + public void onData(Stream stream, DataFrame frame) + { + + } + + @Override + public void onFailure(Stream stream, Throwable x) + { + + } + } + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java new file mode 100644 index 00000000000..3eb90e8867b --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java @@ -0,0 +1,34 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.api.server; + +import org.eclipse.jetty.http2.api.Session; + +public interface ServerSessionListener extends Session.Listener +{ + public void onConnect(Session session); + + public static class Adapter extends Session.Listener.Adapter implements ServerSessionListener + { + @Override + public void onConnect(Session session) + { + } + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Flag.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Flag.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/Frame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java similarity index 70% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java index 01df9ab37ac..eef67a45e64 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java @@ -18,20 +18,40 @@ package org.eclipse.jetty.http2.frames; -import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http2.hpack.MetaData; public class HeadersFrame { private final int streamId; - private final HttpFields fields; + private final MetaData metaData; private final PriorityFrame priority; private final boolean endStream; - public HeadersFrame(int streamId, HttpFields fields, PriorityFrame priority, boolean endStream) + public HeadersFrame(int streamId, MetaData metaData, PriorityFrame priority, boolean endStream) { this.streamId = streamId; - this.fields = fields; + this.metaData = metaData; this.priority = priority; this.endStream = endStream; } + + public int getStreamId() + { + return streamId; + } + + public MetaData getMetaData() + { + return metaData; + } + + public PriorityFrame getPriority() + { + return priority; + } + + public boolean isEndStream() + { + return endStream; + } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java similarity index 91% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 6fefe05c0f2..09373568d77 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -21,11 +21,11 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; import java.util.Map; -import org.eclipse.jetty.hpack.HpackEncoder; -import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.hpack.HpackEncoder; +import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; @@ -37,7 +37,7 @@ public class Generator public Generator(ByteBufferPool byteBufferPool) { this.byteBufferPool = byteBufferPool; - this.encoder = new HpackEncoder(byteBufferPool); + this.encoder = new HpackEncoder(); } public ByteBufferPool.Lease generateData(int streamId, ByteBuffer data, boolean last, boolean compress, byte[] paddingBytes) @@ -82,7 +82,7 @@ public class Generator return lease; } - public ByteBufferPool.Lease generateHeaders(int streamId, HttpFields headers, boolean contentFollows, byte[] paddingBytes) + public ByteBufferPool.Lease generateHeaders(int streamId, MetaData metaData, boolean contentFollows, byte[] paddingBytes) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); @@ -93,9 +93,11 @@ public class Generator int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; - ByteBufferPool.Lease hpackBuffers = encoder.encode(headers); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - long hpackLength = hpackBuffers.getTotalLength(); + encoder.encode(metaData, lease); + + long hpackLength = lease.getTotalLength(); long length = extraPaddingBytes + hpackLength + paddingLength; if (length > Frame.MAX_LENGTH) @@ -116,16 +118,12 @@ public class Generator else if (extraPaddingBytes == 1) header.put((byte)paddingLength); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - BufferUtil.flipToFlush(header, 0); - lease.add(header, true); - - lease.merge(hpackBuffers); + lease.prepend(header, true); if (paddingBytes != null) { - lease.add(ByteBuffer.wrap(paddingBytes), false); + lease.append(ByteBuffer.wrap(paddingBytes), false); } return lease; @@ -150,7 +148,7 @@ public class Generator header.put((byte)weight); BufferUtil.flipToFlush(header, 0); - lease.add(header, true); + lease.append(header, true); return lease; } @@ -167,7 +165,7 @@ public class Generator header.putInt(error); BufferUtil.flipToFlush(header, 0); - lease.add(header, true); + lease.append(header, true); return lease; } @@ -185,7 +183,7 @@ public class Generator } BufferUtil.flipToFlush(header, 0); - lease.add(header, true); + lease.append(header, true); return lease; } @@ -202,7 +200,7 @@ public class Generator header.put(payload); BufferUtil.flipToFlush(header, 0); - lease.add(header, true); + lease.append(header, true); return lease; } @@ -226,7 +224,7 @@ public class Generator } BufferUtil.flipToFlush(header, 0); - lease.add(header, true); + lease.append(header, true); return lease; } @@ -245,7 +243,7 @@ public class Generator header.putInt(windowUpdate); BufferUtil.flipToFlush(header, 0); - lease.add(header, true); + lease.append(header, true); return lease; } @@ -273,13 +271,13 @@ public class Generator header.put((byte)paddingLength); BufferUtil.flipToFlush(header, 0); - lease.add(header, true); + lease.append(header, true); - lease.add(data, false); + lease.append(data, false); if (paddingBytes != null) { - lease.add(ByteBuffer.wrap(paddingBytes), false); + lease.append(ByteBuffer.wrap(paddingBytes), false); } } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java new file mode 100644 index 00000000000..1a8fb509fc5 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java @@ -0,0 +1,83 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.hpack.HpackDecoder; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; + +public class HeaderBlockParser +{ + private final ByteBufferPool byteBufferPool; + private final HpackDecoder hpackDecoder; + private ByteBuffer blockBuffer; + + public HeaderBlockParser(ByteBufferPool byteBufferPool, HpackDecoder hpackDecoder) + { + this.byteBufferPool = byteBufferPool; + this.hpackDecoder = hpackDecoder; + } + + public MetaData parse(ByteBuffer buffer, int blockLength) + { + // We must wait for the all the bytes of the header block to arrive. + // If they are not all available, accumulate them. + // When all are available, decode them. + + int accumulated = blockBuffer == null ? 0 : blockBuffer.position(); + int remaining = blockLength - accumulated; + + if (buffer.remaining() < remaining) + { + if (blockBuffer == null) + { + blockBuffer = byteBufferPool.acquire(blockLength, false); + BufferUtil.clearToFill(blockBuffer); + } + blockBuffer.put(buffer); + return null; + } + else + { + int limit = buffer.limit(); + buffer.limit(buffer.position() + remaining); + ByteBuffer toDecode; + if (blockBuffer != null) + { + blockBuffer.put(buffer); + BufferUtil.flipToFlush(blockBuffer, 0); + toDecode = blockBuffer; + } + else + { + toDecode = buffer; + } + + MetaData result = hpackDecoder.decode(toDecode); + + buffer.limit(limit); + byteBufferPool.release(blockBuffer); + + return result; + } + } +} diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java similarity index 87% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 0d92dd40bd3..448efe3181e 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -20,13 +20,14 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; -import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; +import org.eclipse.jetty.http2.hpack.MetaData; public class HeadersBodyParser extends BodyParser { + private final HeaderBlockParser headerBlockParser; private State state = State.PREPARE; private int cursor; private int length; @@ -34,11 +35,11 @@ public class HeadersBodyParser extends BodyParser private boolean exclusive; private int streamId; private int weight; - private HttpFields fields; - public HeadersBodyParser(HeaderParser headerParser, Parser.Listener listener) + public HeadersBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser) { super(headerParser, listener); + this.headerBlockParser = headerBlockParser; } private void reset() @@ -50,7 +51,6 @@ public class HeadersBodyParser extends BodyParser exclusive = false; streamId = 0; weight = 0; - fields = null; } @Override @@ -63,7 +63,6 @@ public class HeadersBodyParser extends BodyParser case PREPARE: { length = getBodyLength(); - fields = new HttpFields(); if (isPaddingHigh()) { state = State.PADDING_HIGH; @@ -168,12 +167,20 @@ public class HeadersBodyParser extends BodyParser } case HEADERS: { - // TODO: use HpackDecoder - - state = State.PADDING; - if (onHeaders(streamId, weight, exclusive, fields)) + int blockLength = length - paddingLength; + if (blockLength < 0) { - return Result.ASYNC; + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + } + MetaData metaData = headerBlockParser.parse(buffer, blockLength); + if (metaData != null) + { + length -= blockLength; + state = State.PADDING; + if (onHeaders(streamId, weight, exclusive, metaData)) + { + return Result.ASYNC; + } } break; } @@ -198,14 +205,14 @@ public class HeadersBodyParser extends BodyParser return Result.PENDING; } - private boolean onHeaders(int streamId, int weight, boolean exclusive, HttpFields fields) + private boolean onHeaders(int streamId, int weight, boolean exclusive, MetaData metaData) { PriorityFrame priorityFrame = null; if (hasFlag(Flag.PRIORITY)) { priorityFrame = new PriorityFrame(streamId, getStreamId(), weight, exclusive); } - HeadersFrame frame = new HeadersFrame(getStreamId(), fields, priorityFrame, isEndStream()); + HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, priorityFrame, isEndStream()); return notifyHeaders(frame); } diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java similarity index 95% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index bca7252f306..b1d7f843d39 100644 --- a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -29,6 +29,8 @@ import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; +import org.eclipse.jetty.http2.hpack.HpackDecoder; +import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -41,11 +43,14 @@ public class Parser private final Listener listener; private State state = State.HEADER; - public Parser(Listener listener) + public Parser(ByteBufferPool byteBufferPool, Listener listener) { this.listener = listener; + + HeaderBlockParser headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder()); + bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener); - bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener); + bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser); bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); bodyParsers[FrameType.SETTINGS.getType()] = new SettingsBodyParser(headerParser, listener); diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java diff --git a/jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java similarity index 100% rename from jetty-http2/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/api/UsageTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/api/UsageTest.java new file mode 100644 index 00000000000..611649a4bfa --- /dev/null +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/api/UsageTest.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.api; + +import org.junit.Ignore; +import org.junit.Test; + +public class UsageTest +{ + @Ignore + @Test + public void test() throws Exception + { +// HTTP2Client client = new HTTP2Client(); +// client.connect("localhost", 8080, new Promise.Adapter() +// { +// @Override +// public void succeeded(Session session) +// { +// session.newStream(new HeadersFrame(0, info, null, true), new Stream.Listener.Adapter() +// { +// @Override +// public void onData(Stream stream, DataFrame frame) +// { +// System.out.println("received frame = " + frame); +// } +// }, new Adapter() +// { +// @Override +// public void succeeded(Stream stream) +// { +// DataFrame frame = new DataFrame(stream.getId(), ByteBuffer.wrap("HELLO".getBytes(StandardCharsets.UTF_8)), true); +// stream.data(frame, new Callback.Adapter()); +// } +// }); +// } +// }); + + // KINDA CALLBACK HELL ABOVE. + // BELOW USING COMPLETABLES: + +// client.connect("localhost", 8080).then(session -> session.newStream(...)).then(stream -> stream.data(...)); + } +} diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java similarity index 97% rename from jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java rename to jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 1d1256b5fea..44736009a6a 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -144,7 +144,7 @@ public class DataGenerateParseTest lease = lease.merge(generator.generateData(13, data[j - 1].slice(), j == data.length, false, new byte[paddingLength])); } - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onData(DataFrame frame) @@ -172,7 +172,7 @@ public class DataGenerateParseTest ByteBufferPool.Lease lease = generator.generateData(13, ByteBuffer.wrap(largeContent).slice(), true, false, new byte[1024]); final List frames = new ArrayList<>(); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onData(DataFrame frame) diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java similarity index 95% rename from jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java rename to jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java index 21f7ad9e8d7..b98115249ff 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java @@ -47,7 +47,7 @@ public class GoAwayGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = generator.generateGoAway(lastStreamId, error, null); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onGoAway(GoAwayFrame frame) @@ -86,7 +86,7 @@ public class GoAwayGenerateParseTest final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = generator.generateGoAway(lastStreamId, error, payload); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onGoAway(GoAwayFrame frame) diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java similarity index 100% rename from jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java rename to jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java similarity index 95% rename from jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java rename to jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java index a5b8e27bbc8..56595f93458 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -47,7 +47,7 @@ public class PingGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = generator.generatePing(payload, true); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onPing(PingFrame frame) @@ -83,7 +83,7 @@ public class PingGenerateParseTest final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = generator.generatePing(payload, true); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onPing(PingFrame frame) diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java similarity index 95% rename from jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java rename to jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index e094bdd5685..33b86c8edfe 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -48,7 +48,7 @@ public class PriorityGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onPriority(PriorityFrame frame) @@ -88,7 +88,7 @@ public class PriorityGenerateParseTest final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onPriority(PriorityFrame frame) diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java similarity index 95% rename from jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java rename to jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index 69f27bd1135..3bf0e44c6bc 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -46,7 +46,7 @@ public class ResetGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = generator.generateReset(streamId, error); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onReset(ResetFrame frame) @@ -82,7 +82,7 @@ public class ResetGenerateParseTest final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = generator.generateReset(streamId, error); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onReset(ResetFrame frame) diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java similarity index 95% rename from jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java rename to jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index 9e07554ad31..644ac83eb82 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -76,7 +76,7 @@ public class SettingsGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = generator.generateSettings(settings, true); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onSettings(SettingsFrame frame) @@ -111,7 +111,7 @@ public class SettingsGenerateParseTest bytes.putShort(0, (short)(bytes.getShort(0) - 1)); final AtomicInteger errorRef = new AtomicInteger(); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) @@ -143,7 +143,7 @@ public class SettingsGenerateParseTest final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = generator.generateSettings(settings1, true); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onSettings(SettingsFrame frame) diff --git a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java similarity index 95% rename from jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java rename to jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java index 273b59a148f..c3c5168f55a 100644 --- a/jetty-http2/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java @@ -46,7 +46,7 @@ public class WindowUpdateGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = generator.generateWindowUpdate(streamId, windowUpdate); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onWindowUpdate(WindowUpdateFrame frame) @@ -82,7 +82,7 @@ public class WindowUpdateGenerateParseTest final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = generator.generateWindowUpdate(streamId, windowUpdate); - Parser parser = new Parser(new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override public boolean onWindowUpdate(WindowUpdateFrame frame) diff --git a/jetty-hpack/pom.xml b/jetty-http2/http2-hpack/pom.xml similarity index 68% rename from jetty-hpack/pom.xml rename to jetty-http2/http2-hpack/pom.xml index c69b6798115..26866091022 100644 --- a/jetty-hpack/pom.xml +++ b/jetty-http2/http2-hpack/pom.xml @@ -1,17 +1,15 @@ - jetty-project - org.eclipse.jetty + org.eclipse.jetty.http2 + http2-parent 10.0.0-SNAPSHOT + 4.0.0 - jetty-hpack - Jetty :: HPACK Utility - http://www.eclipse.org/jetty - - ${project.groupId}.http - + http2-hpack + Jetty :: HTTP2 :: HPACK + org.eclipse.jetty @@ -34,6 +32,7 @@ test + @@ -56,33 +55,13 @@ org.apache.maven.plugins maven-jar-plugin - - - artifact-jar - - jar - - - - test-jar - - test-jar - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.http.* - - + diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java similarity index 99% rename from jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java rename to jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 00626d5d22c..b0903cdc532 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; import java.util.HashMap; diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java similarity index 98% rename from jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java rename to jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 60bfa320bea..eb77c4f4c9d 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -17,13 +17,13 @@ // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; -import org.eclipse.jetty.hpack.HpackContext.Entry; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http2.hpack.HpackContext.Entry; /* ------------------------------------------------------------ */ diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java similarity index 98% rename from jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java rename to jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 38db9ce7c07..6460d965df8 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -17,17 +17,15 @@ // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; import java.util.EnumSet; -import org.eclipse.jetty.hpack.HpackContext.Entry; import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.io.ByteBufferPool.Lease; public class HpackEncoder diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java similarity index 99% rename from jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java rename to jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java index b034e041f87..8889ff4bb7b 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/Huffman.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java @@ -16,9 +16,8 @@ // ======================================================================== // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; -import java.io.IOException; import java.nio.ByteBuffer; public class Huffman diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaData.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java similarity index 98% rename from jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaData.java rename to jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java index c07a7dda7ed..4228638f975 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaData.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java @@ -17,7 +17,7 @@ // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; import java.util.Iterator; diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java similarity index 98% rename from jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaDataBuilder.java rename to jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 8d54af096c7..549996fc3d6 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -17,7 +17,7 @@ // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; import java.util.ArrayList; import java.util.List; @@ -126,4 +126,4 @@ public class MetaDataBuilder _fields.clear(); } } -} \ No newline at end of file +} diff --git a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java similarity index 99% rename from jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java rename to jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java index c1e39c07ba4..6a562e4497d 100644 --- a/jetty-hpack/src/main/java/org/eclipse/jetty/hpack/NBitInteger.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java similarity index 99% rename from jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java rename to jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java index a61c215e3b0..138980ded20 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackContextTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java @@ -17,26 +17,26 @@ // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - import java.nio.ByteBuffer; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; -import org.eclipse.jetty.hpack.HpackContext.Entry; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + /* ------------------------------------------------------------ */ /** diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java similarity index 93% rename from jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java rename to jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index dd490f49162..ee9bc011e14 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -17,9 +17,7 @@ // -package org.eclipse.jetty.hpack; - -import static org.junit.Assert.*; +package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; import java.util.Iterator; @@ -30,6 +28,10 @@ import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.util.TypeUtil; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + /* ------------------------------------------------------------ */ /** @@ -49,7 +51,7 @@ public class HpackDecoderTest MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET",request.getMethodString()); + assertEquals("GET", request.getMethodString()); assertEquals(HttpScheme.HTTP,request.getScheme()); assertEquals("/",request.getPath()); assertEquals("www.example.com",request.getAuthority()); @@ -63,7 +65,7 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET",request.getMethodString()); + assertEquals("GET", request.getMethodString()); assertEquals(HttpScheme.HTTP,request.getScheme()); assertEquals("/",request.getPath()); assertEquals("www.example.com",request.getAuthority()); @@ -104,7 +106,7 @@ public class HpackDecoderTest MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET",request.getMethodString()); + assertEquals("GET", request.getMethodString()); assertEquals(HttpScheme.HTTP,request.getScheme()); assertEquals("/",request.getPath()); assertEquals("www.example.com",request.getAuthority()); @@ -118,7 +120,7 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET",request.getMethodString()); + assertEquals("GET", request.getMethodString()); assertEquals(HttpScheme.HTTP,request.getScheme()); assertEquals("/",request.getPath()); assertEquals("www.example.com",request.getAuthority()); diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java similarity index 98% rename from jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java rename to jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index eb343b4d00c..082f588901d 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -17,22 +17,22 @@ // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; -import static org.junit.Assert.assertThat; - import java.nio.ByteBuffer; import java.util.HashSet; -import org.eclipse.jetty.hpack.HpackContext.Entry; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; +import static org.junit.Assert.assertThat; + /* ------------------------------------------------------------ */ /** diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java similarity index 96% rename from jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackTest.java rename to jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index 1c0f77c68b6..da75ce2a1ff 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -17,7 +17,7 @@ // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; import org.eclipse.jetty.http.HttpFields; import org.junit.Test; diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java similarity index 98% rename from jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java rename to jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java index a6f19157ce2..a0acecf3158 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/HuffmanTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java @@ -16,13 +16,13 @@ // ======================================================================== // -package org.eclipse.jetty.hpack; +package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; -import org.junit.Assert; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; +import org.junit.Assert; import org.junit.Test; public class HuffmanTest diff --git a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java similarity index 99% rename from jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java rename to jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java index 32698e5d8f4..8de3a29fc76 100644 --- a/jetty-hpack/src/test/java/org/eclipse/jetty/hpack/NBitIntegerTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java @@ -16,9 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.hpack; - -import static org.junit.Assert.assertEquals; +package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; @@ -27,6 +25,8 @@ import org.eclipse.jetty.util.TypeUtil; import org.junit.Assert; import org.junit.Test; +import static org.junit.Assert.assertEquals; + public class NBitIntegerTest { diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml new file mode 100644 index 00000000000..62544c9444d --- /dev/null +++ b/jetty-http2/http2-server/pom.xml @@ -0,0 +1,59 @@ + + + + org.eclipse.jetty.http2 + http2-parent + 10.0.0-SNAPSHOT + + + 4.0.0 + http2-server + Jetty :: HTTP2 :: Server + + + + + org.apache.felix + maven-bundle-plugin + true + + + + manifest + + + + javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,* + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + + + + org.eclipse.jetty + http2-common + ${project.version} + + + org.eclipse.jetty + jetty-server + ${project.version} + + + + diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java new file mode 100644 index 00000000000..d2ef7e271eb --- /dev/null +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -0,0 +1,109 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import org.eclipse.jetty.http2.HTTP2Connection; +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.AbstractConnectionFactory; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory +{ + private static final Logger LOG = Log.getLogger(HTTP2ServerConnectionFactory.class); + private final HttpConfiguration httpConfiguration; + + public HTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration) + { + super("h2"); + this.httpConfiguration = httpConfiguration; + } + + @Override + public Connection newConnection(Connector connector, EndPoint endPoint) + { + Session.Listener listener = new HTTPServerSessionListener(connector, httpConfiguration, endPoint); + + HTTP2Session session = new HTTP2ServerSession(listener); + + Parser parser = new Parser(connector.getByteBufferPool(), session); + HTTP2Connection connection = new HTTP2Connection(connector.getByteBufferPool(), connector.getExecutor(), + endPoint, parser, getInputBufferSize()); + + return configure(connection, connector, endPoint); + } + + private class HTTPServerSessionListener extends ServerSessionListener.Adapter implements Stream.Listener + { + private final Connector connector; + private final HttpConfiguration httpConfiguration; + private final EndPoint endPoint; + + public HTTPServerSessionListener(Connector connector, HttpConfiguration httpConfiguration, EndPoint endPoint) + { + + this.connector = connector; + this.httpConfiguration = httpConfiguration; + this.endPoint = endPoint; + } + + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + LOG.debug("Received {} on {}", frame, stream); + + HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2(); + HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); + HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input); + // TODO: link channel to stream. + +// if (frame.getMetaData().isEmpty()) +// { + // TODO: abort. +// return null; +// } + + channel.requestStart(frame); + + return frame.isEndStream() ? null : this; + } + + @Override + public void onData(Stream stream, DataFrame frame) + { + + } + + @Override + public void onFailure(Stream stream, Throwable x) + { + + } + } +} diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java new file mode 100644 index 00000000000..afaa79bb5b4 --- /dev/null +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -0,0 +1,54 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.HTTP2Stream; +import org.eclipse.jetty.http2.IStream; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.HeadersFrame; + +public class HTTP2ServerSession extends HTTP2Session +{ + private final ConcurrentMap streams = new ConcurrentHashMap<>(); + + public HTTP2ServerSession(Listener listener) + { + super(listener); + } + + @Override + public boolean onHeaders(HeadersFrame frame) + { + // TODO: handle max concurrent streams + // TODO: handle duplicate streams + + IStream stream = new HTTP2Stream(); + IStream existing = streams.putIfAbsent(stream.getId(), stream); + if (existing == null) + { + Stream.Listener listener = notifyNewStream(stream, frame); + stream.setListener(listener); + } + return false; + } +} diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java new file mode 100644 index 00000000000..0dd7274348a --- /dev/null +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -0,0 +1,53 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpChannel; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpInput; +import org.eclipse.jetty.server.HttpTransport; +import org.eclipse.jetty.util.BufferUtil; + +public class HttpChannelOverHTTP2 extends HttpChannel +{ + public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) + { + super(connector, configuration, endPoint, transport, input); + } + + public void requestStart(HeadersFrame frame) + { + // TODO: extract method, etc. + HttpMethod httpMethod = null; + String method = null; + ByteBuffer uri = BufferUtil.toBuffer(0); + HttpVersion version = null; + + startRequest(httpMethod, method, uri, version); + + // TODO: See SPDY's + } +} diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java new file mode 100644 index 00000000000..e0ac508d81b --- /dev/null +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java @@ -0,0 +1,48 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.server.QueuedHttpInput; + +public class HttpInputOverHTTP2 extends QueuedHttpInput +{ + @Override + protected void onContentConsumed(ByteBuffer item) + { + } + + @Override + protected int remaining(ByteBuffer item) + { + return 0; + } + + @Override + protected int get(ByteBuffer item, byte[] buffer, int offset, int length) + { + return 0; + } + + @Override + protected void consume(ByteBuffer item, int length) + { + } +} diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java new file mode 100644 index 00000000000..685e6d9ee5e --- /dev/null +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -0,0 +1,48 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpGenerator; +import org.eclipse.jetty.server.HttpTransport; +import org.eclipse.jetty.util.Callback; + +public class HttpTransportOverHTTP2 implements HttpTransport +{ + @Override + public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) + { + } + + @Override + public void send(ByteBuffer content, boolean lastContent, Callback callback) + { + } + + @Override + public void completed() + { + } + + @Override + public void abort() + { + } +} diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index 9c5d3da7bbe..7aadaaaa321 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -5,40 +5,19 @@ org.eclipse.jetty 10.0.0-SNAPSHOT + 4.0.0 - jetty-http2 - Jetty :: Http2 Utility - http://www.eclipse.org/jetty - - ${project.groupId}.http - - - - org.eclipse.jetty - jetty-http - ${project.version} - - - org.eclipse.jetty - jetty-hpack - ${project.version} - - - org.eclipse.jetty - jetty-io - ${project.version} - - - org.eclipse.jetty - jetty-util - ${project.version} - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - + org.eclipse.jetty.http2 + http2-parent + pom + Jetty :: HTTP2 + + + http2-hpack + http2-common + http2-server + + @@ -52,7 +31,9 @@ - javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,* + org.eclipse.jetty.http2.*;version="9.1" + org.eclipse.jetty.*;version="[9.0,10.0)",* + <_nouses>true @@ -61,33 +42,13 @@ org.apache.maven.plugins maven-jar-plugin - - - artifact-jar - - jar - - - - test-jar - - test-jar - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.http.* - - + diff --git a/pom.xml b/pom.xml index 469f79110fa..4b732b4682f 100644 --- a/pom.xml +++ b/pom.xml @@ -418,7 +418,6 @@ jetty-jmx jetty-io jetty-http - jetty-hpack jetty-http2 jetty-continuation jetty-server From bedfda03d2380d07db32373f0de117756c497333 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 9 Jun 2014 14:01:51 +0200 Subject: [PATCH 031/269] Introduced Lease.prepend(). --- .../org/eclipse/jetty/io/ByteBufferPool.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index e4934f6964b..61c78fcb853 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -64,15 +64,20 @@ public interface ByteBufferPool this.recycles = new ArrayList<>(); } - public ByteBuffer acquire(int capacity,boolean direct) + public ByteBuffer acquire(int capacity, boolean direct) { - ByteBuffer buffer = byteBufferPool.acquire(capacity,direct); - buffers.add(buffer); - recycles.add(true); + ByteBuffer buffer = byteBufferPool.acquire(capacity, direct); + append(buffer, true); return buffer; } - - public void add(ByteBuffer buffer, boolean recycle) + + public void prepend(ByteBuffer buffer, boolean recycle) + { + buffers.add(0, buffer); + recycles.add(0, recycle); + } + + public void append(ByteBuffer buffer, boolean recycle) { buffers.add(buffer); recycles.add(recycle); From b2296cc2d4ae6619a74f2a9c608f8a816d4ba354 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 9 Jun 2014 14:12:46 +0200 Subject: [PATCH 032/269] simplified startRequest --- .../org/eclipse/jetty/http/HttpParser.java | 31 ++++++++++--------- .../org/eclipse/jetty/http/HttpTester.java | 6 ++-- .../eclipse/jetty/http/HttpParserTest.java | 15 +++------ jetty-http2/http2-common/pom.xml | 2 +- jetty-http2/http2-server/pom.xml | 2 +- .../http2/server/HttpChannelOverHTTP2.java | 6 ++-- .../org/eclipse/jetty/server/HttpChannel.java | 26 ++++++---------- .../org/eclipse/jetty/server/Request.java | 15 ++++----- .../jetty/server/ExtendedServerTest.java | 6 ++-- .../spdy/server/http/HttpChannelOverSPDY.java | 7 ++--- .../server/proxy/ProxyHTTPSPDYConnection.java | 5 +-- 11 files changed, 53 insertions(+), 68 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 79f1c28d90d..d7c46e2099c 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -33,7 +33,7 @@ import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ -/** A Parser for HTTP 0.9, 1.0 and 1.1 +/** A Parser for 1.0 and 1.1 *

* The is parser parses HTTP client and server messages from buffers * passed in the {@link #parseNext(ByteBuffer)} method. The parsed @@ -142,6 +142,7 @@ public class HttpParser private String _methodString; private HttpVersion _version; private ByteBuffer _uri=ByteBuffer.allocate(INITIAL_URI_LENGTH); // Tune? + private HttpURI _httpURI=new HttpURI(StandardCharsets.UTF_8); private EndOfContent _endOfContent; private long _contentLength; private long _contentPosition; @@ -618,11 +619,7 @@ public class HttpParser { // HTTP/0.9 _uri.flip(); - handle=_requestHandler.startRequest(_method,_methodString,_uri,null)||handle; - setState(State.END); - BufferUtil.clear(buffer); - handle=_handler.headerComplete()||handle; - handle=_handler.messageComplete()||handle; + throw new BadMessage("HTTP/0.9 not supported"); } else { @@ -713,11 +710,7 @@ public class HttpParser { // HTTP/0.9 _uri.flip(); - handle=_requestHandler.startRequest(_method,_methodString,_uri, null)||handle; - setState(State.END); - BufferUtil.clear(buffer); - handle=_handler.headerComplete()||handle; - handle=_handler.messageComplete()||handle; + throw new BadMessage("HTTP/0.9 not supported"); } } else if (ch<0) @@ -744,7 +737,13 @@ public class HttpParser setState(State.HEADER); _uri.flip(); - handle=_requestHandler.startRequest(_method,_methodString,_uri, _version)||handle; + + if (_method == HttpMethod.CONNECT) + _httpURI.parseConnect(_uri.array(),_uri.arrayOffset()+_uri.position(),_uri.remaining()); + else + _httpURI.parse(_uri.array(),_uri.arrayOffset()+_uri.position(),_uri.remaining()); + + handle=_requestHandler.startRequest(_methodString,_httpURI, _version)||handle; continue; } else if (ch>=HttpTokens.SPACE) @@ -1567,6 +1566,7 @@ public class HttpParser _contentChunk=null; _headerBytes=0; _host=false; + _httpURI.clear(); } /* ------------------------------------------------------------------------------- */ @@ -1637,17 +1637,18 @@ public class HttpParser void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort); } + + public interface RequestHandler extends HttpHandler { /** * This is the method called by parser when the HTTP request line is parsed - * @param method The method as enum if of a known type - * @param methodString The method as a string + * @param method The method * @param uri The raw bytes of the URI. These are copied into a ByteBuffer that will not be changed until this parser is reset and reused. * @param version * @return true if handling parsing should return. */ - public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version); + public abstract boolean startRequest(String method, HttpURI uri, HttpVersion version); /** * This is the method called by the parser after it has parsed the host header (and checked it's format). This is diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java index 537c457cb41..0385ffcb7e7 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java @@ -256,10 +256,10 @@ public class HttpTester private String _uri; @Override - public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version) + public boolean startRequest(String method, HttpURI uri, HttpVersion version) { - _method=methodString; - _uri=BufferUtil.toUTF8String(uri); + _method=method; + _uri=uri.toString(); _version=version; return false; } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 6bc6ae23e48..12b2b389087 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -86,10 +86,8 @@ public class HttpParserTest HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); - assertEquals("GET", _methodOrVersion); - assertEquals("/999", _uriOrStatus); - assertEquals(null, _versionOrReason); - assertEquals(-1, _headers); + + assertEquals("HTTP/0.9 not supported", _bad); } @Test @@ -101,10 +99,7 @@ public class HttpParserTest HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); - assertEquals("POST", _methodOrVersion); - assertEquals("/222", _uriOrStatus); - assertEquals(null, _versionOrReason); - assertEquals(-1, _headers); + assertEquals("HTTP/0.9 not supported", _bad); } @Test @@ -1504,14 +1499,14 @@ public class HttpParserTest } @Override - public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version) + public boolean startRequest(String method, HttpURI uri, HttpVersion version) { _fields.clear(); _headers= -1; _hdr= new String[10]; _val= new String[10]; _methodOrVersion= method; - _uriOrStatus= BufferUtil.toUTF8String(uri); + _uriOrStatus= uri.toString(); _versionOrReason= version==null?null:version.asString(); fields=new HttpFields(); diff --git a/jetty-http2/http2-common/pom.xml b/jetty-http2/http2-common/pom.xml index 0ea64885cb8..4b150f04e99 100644 --- a/jetty-http2/http2-common/pom.xml +++ b/jetty-http2/http2-common/pom.xml @@ -12,7 +12,7 @@ - org.eclipse.jetty + org.eclipse.jetty.http2 http2-hpack ${project.version} diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index 62544c9444d..d0bd72672c4 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -45,7 +45,7 @@ - org.eclipse.jetty + org.eclipse.jetty.http2 http2-common ${project.version} diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 0dd7274348a..5be1a9beb3f 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.server; import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.io.EndPoint; @@ -41,12 +42,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel public void requestStart(HeadersFrame frame) { // TODO: extract method, etc. - HttpMethod httpMethod = null; String method = null; - ByteBuffer uri = BufferUtil.toBuffer(0); + HttpURI uri = new HttpURI("/foo/bar"); HttpVersion version = null; - startRequest(httpMethod, method, uri, version); + startRequest(method, uri, version); // TODO: See SPDY's } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 07b09ab7241..b8abcaec280 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -36,7 +36,6 @@ import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator.ResponseInfo; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; -import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; @@ -99,7 +98,6 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H private final HttpConfiguration _configuration; private final EndPoint _endPoint; private final HttpTransport _transport; - private final HttpURI _uri; private final HttpChannelState _state; private final Request _request; private final Response _response; @@ -115,7 +113,6 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H _endPoint = endPoint; _transport = transport; - _uri = new HttpURI(URIUtil.__CHARSET); _state = new HttpChannelState(this); input.init(_state); _request = new Request(this, input); @@ -232,7 +229,6 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H _expect102Processing = false; _request.recycle(); _response.recycle(); - _uri.clear(); } @Override @@ -255,7 +251,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H if (LOG.isDebugEnabled()) { threadName = Thread.currentThread().getName(); - Thread.currentThread().setName(threadName + " - " + _uri); + Thread.currentThread().setName(threadName + " - " + _request.getUri()); } HttpChannelState.Action action = _state.handling(); @@ -363,7 +359,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H if (e instanceof EofException) LOG.debug(e); else - LOG.warn(String.valueOf(_uri), e); + LOG.warn(String.valueOf(_request.getUri()), e); _state.error(e); _request.setHandled(true); handleException(e); @@ -492,38 +488,34 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H } @Override - public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version) + public boolean startRequest(String method, HttpURI uri, HttpVersion version) { _expect = false; _expect100Continue = false; _expect102Processing = false; _request.setTimeStamp(System.currentTimeMillis()); - _request.setMethod(httpMethod, method); + _request.setMethod(method); - if (httpMethod == HttpMethod.CONNECT) - _uri.parseConnect(uri.array(),uri.arrayOffset()+uri.position(),uri.remaining()); - else - _uri.parse(uri.array(),uri.arrayOffset()+uri.position(),uri.remaining()); - _request.setUri(_uri); + _request.setUri(uri); String path; try { - path = _uri.getDecodedPath(); + path = uri.getDecodedPath(); } catch (Exception e) { LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1"); LOG.ignore(e); - path = _uri.getDecodedPath(StandardCharsets.ISO_8859_1); + path = uri.getDecodedPath(StandardCharsets.ISO_8859_1); } String info = URIUtil.canonicalPath(path); if (info == null) { - if( path==null && _uri.getScheme()!=null &&_uri.getHost()!=null) + if( path==null && uri.getScheme()!=null &&uri.getHost()!=null) { info = "/"; _request.setRequestURI(""); @@ -610,7 +602,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H @Override public boolean parsedHostHeader(String host, int port) { - if (_uri.getHost()==null) + if (_request.getUri().getHost()==null) { _request.setServerName(host); _request.setServerPort(port); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 77c80abc293..eb790fc8068 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -182,8 +182,7 @@ public class Request implements HttpServletRequest private CookieCutter _cookies; private DispatcherType _dispatcherType; private int _inputState = __NONE; - private HttpMethod _httpMethod; - private String _httpMethodString; + private String _httpMethod; private MultiMap _queryParameters; private MultiMap _contentParameters; private MultiMap _parameters; @@ -813,7 +812,7 @@ public class Request implements HttpServletRequest @Override public String getMethod() { - return _httpMethodString; + return _httpMethod; } /* ------------------------------------------------------------ */ @@ -1631,8 +1630,7 @@ public class Request implements HttpServletRequest _context = null; _newContext=false; _serverName = null; - _httpMethod=null; - _httpMethodString = null; + _httpMethod = null; _pathInfo = null; _port = 0; _httpVersion = HttpVersion.HTTP_1_1; @@ -1875,16 +1873,15 @@ public class Request implements HttpServletRequest * @param method * The method to set. */ - public void setMethod(HttpMethod httpMethod, String method) + public void setMethod(String method) { - _httpMethod=httpMethod; - _httpMethodString = method; + _httpMethod = method; } /* ------------------------------------------------------------ */ public boolean isHead() { - return HttpMethod.HEAD==_httpMethod; + return HttpMethod.HEAD.asString().equals(_httpMethod); } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java index 4fec16b689e..9ddaaf56e15 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java @@ -30,8 +30,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.SelectChannelEndPoint; @@ -105,10 +105,10 @@ public class ExtendedServerTest extends HttpServerTestBase return new HttpChannelOverHttp(getConnector(), getHttpConfiguration(), getEndPoint(), this, httpInput) { @Override - public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version) + public boolean startRequest(String method, HttpURI uri, HttpVersion version) { getRequest().setAttribute("DispatchedAt",((ExtendedEndPoint)getEndPoint()).getLastSelected()); - return super.startRequest(httpMethod,method,uri,version); + return super.startRequest(method,uri,version); } }; } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index d032aa1c9e3..304f71fb874 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; @@ -180,12 +181,10 @@ public class HttpChannelOverSPDY extends HttpChannel HttpMethod httpMethod = HttpMethod.fromString(methodHeader.getValue()); HttpVersion httpVersion = HttpVersion.fromString(versionHeader.getValue()); - // TODO should handle URI as byte buffer as some bad clients send WRONG encodings in query string - // that we have to deal with - ByteBuffer uri = BufferUtil.toBuffer(uriHeader.getValue()); + HttpURI uri = new HttpURI(uriHeader.getValue()); LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion); - startRequest(httpMethod, httpMethod.asString(), uri, httpVersion); + startRequest(methodHeader.getValue(), uri, httpVersion); Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version)); if (schemeHeader != null) diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java index 2cd07d3ea97..26c5b6b055d 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java @@ -29,6 +29,7 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; @@ -81,13 +82,13 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse } @Override - public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion httpVersion) + public boolean startRequest(String methodString, HttpURI uri, HttpVersion httpVersion) { Connector connector = getConnector(); String scheme = connector.getConnectionFactory(SslConnectionFactory.class) != null ? "https" : "http"; headers.put(HTTPSPDYHeader.SCHEME.name(version), scheme); headers.put(HTTPSPDYHeader.METHOD.name(version), methodString); - headers.put(HTTPSPDYHeader.URI.name(version), BufferUtil.toUTF8String(uri)); // TODO handle bad encodings + headers.put(HTTPSPDYHeader.URI.name(version), uri.toString()); headers.put(HTTPSPDYHeader.VERSION.name(version), httpVersion.asString()); return false; } From 3c321e9b8f049c96ecb7e9b35c1cddebef71673c Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 9 Jun 2014 15:34:09 +0200 Subject: [PATCH 033/269] split authority field and hold results in header table --- .../org/eclipse/jetty/http/HttpParser.java | 2 +- .../jetty/http2/hpack/AuthorityHttpField.java | 94 +++++++++++++++++++ .../jetty/http2/hpack/HpackContext.java | 2 +- .../jetty/http2/hpack/HpackDecoder.java | 9 +- .../jetty/http2/hpack/HpackEncoder.java | 2 +- .../eclipse/jetty/http2/hpack/MetaData.java | 40 ++++++-- .../jetty/http2/hpack/MetaDataBuilder.java | 29 +++--- .../jetty/http2/hpack/HpackDecoderTest.java | 20 ++-- .../org/eclipse/jetty/server/Request.java | 2 +- .../org/eclipse/jetty/util/StringUtil.java | 10 +- 10 files changed, 157 insertions(+), 53 deletions(-) create mode 100644 jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index d7c46e2099c..ac50f342de7 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -842,7 +842,7 @@ public class HttpParser try { len=i; - port = StringUtil.toInt(host.substring(i+1)); + port = StringUtil.toInt(host,i+1); } catch (NumberFormatException e) { diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java new file mode 100644 index 00000000000..e845f1426f6 --- /dev/null +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java @@ -0,0 +1,94 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http2.hpack; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.util.StringUtil; + + +/* ------------------------------------------------------------ */ +/** + */ +public class AuthorityHttpField extends HttpField +{ + public final static String AUTHORITY = HpackContext.STATIC_TABLE[1][0]; + + public final String _host; + public final int _port; + + public AuthorityHttpField(String authority) + { + super(AUTHORITY,authority); + + if (authority.charAt(0)=='[') + { + // ipv6reference + int close=authority.indexOf(']'); + if (close<0) + throw new IllegalArgumentException("Bad ipv6"); + _host=authority.substring(1,close-1); + + if (authority.length()>close+1) + { + if (authority.charAt(close+1)!=':') + throw new IllegalArgumentException("Bad ipv6 port"); + _port=StringUtil.toInt(authority,close+2); + + } + else + _port=0; + } + else + { + // ipv4address or hostname + int c = authority.lastIndexOf(':'); + if (c>=0) + { + _host=authority.substring(0,c); + _port=StringUtil.toInt(authority,c+1); + } + else + { + _host=authority; + _port=0; + } + } + } + + /* ------------------------------------------------------------ */ + /** Get the host. + * @return the host + */ + public String getHost() + { + return _host; + } + + /* ------------------------------------------------------------ */ + /** Get the port. + * @return the port + */ + public int getPort() + { + return _port; + } + + +} diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index b0903cdc532..327033a4d30 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -36,7 +36,7 @@ import org.eclipse.jetty.util.Trie; public class HpackContext { - private static final String[][] STATIC_TABLE = + public static final String[][] STATIC_TABLE = { {null,null}, /* 1 */ {":authority" ,null}, diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index eb77c4f4c9d..06e22ac83bc 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -32,7 +32,6 @@ import org.eclipse.jetty.http2.hpack.HpackContext.Entry; */ public class HpackDecoder { - private final HpackContext _context; private final MetaDataBuilder _builder = new MetaDataBuilder(); @@ -45,7 +44,6 @@ public class HpackDecoder { _context=new HpackContext(maxHeaderTableSize); } - public MetaData decode(ByteBuffer buffer) { @@ -120,7 +118,12 @@ public class HpackDecoder value=toASCIIString(buffer,length); // Make the new field - HttpField field = new HttpField(header,name,value); + HttpField field; + if (":authority".equals(header)) + field = new AuthorityHttpField(value); + else + // Normal Field + field = new HttpField(header,name,value); // emit the field _builder.emit(field); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 6460d965df8..6996d234ee5 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -104,7 +104,7 @@ public class HpackEncoder // TODO optimise these to avoid HttpField creation encode(buffer,new HttpField(":scheme",request.getScheme().asString())); - encode(buffer,new HttpField(":method",request.getMethodString())); + encode(buffer,new HttpField(":method",request.getMethod())); encode(buffer,new HttpField(":authority",request.getAuthority())); // TODO look for host header? encode(buffer,new HttpField(":path",request.getPath())); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java index 4228638f975..f787895f580 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java @@ -19,7 +19,9 @@ package org.eclipse.jetty.http2.hpack; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -55,23 +57,36 @@ public class MetaData implements Iterable return _fields.iterator(); } + public List getFields() + { + if (_fields instanceof List) + return (List)_fields; + ArrayList list = new ArrayList<>(); + for (HttpField field:_fields) + list.add(field); + return list; + } + + /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ public static class Request extends MetaData { - private final HttpMethod _method; - private final String _methodString; + private final String _method; private final HttpScheme _scheme; private final String _authority; + private final String _host; + private final int _port; private final String _path; - public Request(HttpScheme scheme, HttpMethod method, String methodString, String authority, String path, Iterable fields) + public Request(HttpScheme scheme, String method, String authority, String host, int port, String path, Iterable fields) { super(fields); _authority=authority; + _host=host; + _port=port; _method=method; - _methodString=methodString; _path=path; _scheme=scheme; } @@ -88,15 +103,10 @@ public class MetaData implements Iterable return false; } - public HttpMethod getMethod() + public String getMethod() { return _method; } - - public String getMethodString() - { - return _methodString; - } public HttpScheme getScheme() { @@ -108,6 +118,16 @@ public class MetaData implements Iterable return _authority; } + public String getHost() + { + return _host; + } + + public int getPort() + { + return _port; + } + public String getPath() { return _path; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 549996fc3d6..ac8361db408 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -32,10 +32,11 @@ import org.eclipse.jetty.http.HttpScheme; public class MetaDataBuilder { private int _status; - private HttpMethod _method; - private String _methodString; + private String _method; private HttpScheme _scheme; private String _authority; + private String _host; + private int _port; private String _path; List _fields = new ArrayList<>(); @@ -52,25 +53,15 @@ public class MetaDataBuilder break; case ":method": - _method=(HttpMethod)value.getStaticValue(); - _methodString=_method.asString(); + _method=field.getValue(); break; case ":scheme": _scheme = (HttpScheme)value.getStaticValue(); break; - case ":authority": - _authority=field.getValue(); - break; - - case ":path": - _path=field.getValue(); - break; - default: - if (field.getName().charAt(0)!=':') - _fields.add(field); + throw new IllegalArgumentException(); } } else @@ -83,8 +74,7 @@ public class MetaDataBuilder break; case ":method": - _methodString=field.getValue(); - _method=HttpMethod.CACHE.get(_methodString); + _method=field.getValue(); break; case ":scheme": @@ -93,6 +83,9 @@ public class MetaDataBuilder case ":authority": _authority=field.getValue(); + AuthorityHttpField afield=(field instanceof AuthorityHttpField)?((AuthorityHttpField)field):new AuthorityHttpField(field.getValue()); + _host=afield.getHost(); + _port=afield.getPort(); break; case ":path": @@ -111,7 +104,7 @@ public class MetaDataBuilder try { if (_method!=null) - return new MetaData.Request(_scheme,_method,_methodString,_authority,_path,new ArrayList<>(_fields)); + return new MetaData.Request(_scheme,_method,_authority,_host,_port,_path,new ArrayList<>(_fields)); if (_status!=0) return new MetaData.Response(_status,new ArrayList<>(_fields)); return new MetaData(new ArrayList<>(_fields)); @@ -123,6 +116,8 @@ public class MetaDataBuilder _scheme=null; _authority=null; _path=null; + _host=null; + _port=0; _fields.clear(); } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index ee9bc011e14..23a97ccd22b 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -50,8 +50,7 @@ public class HpackDecoderTest MetaData.Request request = (MetaData.Request)decoder.decode(buffer); - assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET", request.getMethodString()); + assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); assertEquals("/",request.getPath()); assertEquals("www.example.com",request.getAuthority()); @@ -64,8 +63,7 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); - assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET", request.getMethodString()); + assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); assertEquals("/",request.getPath()); assertEquals("www.example.com",request.getAuthority()); @@ -81,8 +79,7 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); - assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET",request.getMethodString()); + assertEquals("GET",request.getMethod()); assertEquals(HttpScheme.HTTPS,request.getScheme()); assertEquals("/index.html",request.getPath()); assertEquals("www.example.com",request.getAuthority()); @@ -95,18 +92,15 @@ public class HpackDecoderTest @Test public void testDecodeD_4() { - HpackDecoder decoder = new HpackDecoder(); - // First request String encoded="828786448ce7cf9bebe89b6fb16fa9b6ff"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); - assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET", request.getMethodString()); + assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); assertEquals("/",request.getPath()); assertEquals("www.example.com",request.getAuthority()); @@ -119,8 +113,7 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); - assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET", request.getMethodString()); + assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); assertEquals("/",request.getPath()); assertEquals("www.example.com",request.getAuthority()); @@ -135,8 +128,7 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); - assertEquals(HttpMethod.GET,request.getMethod()); - assertEquals("GET",request.getMethodString()); + assertEquals("GET",request.getMethod()); assertEquals(HttpScheme.HTTPS,request.getScheme()); assertEquals("/index.html",request.getPath()); assertEquals("www.example.com",request.getAuthority()); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index eb790fc8068..8ab8c732626 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -1225,7 +1225,7 @@ public class Request implements HttpServletRequest try { len=i; - _port = StringUtil.toInt(hostPort.substring(i+1)); + _port = StringUtil.toInt(hostPort,i+1); } catch (NumberFormatException e) { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java index 55868ad5edd..cd0e7da27ed 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java @@ -622,17 +622,17 @@ public class StringUtil /** * Convert String to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown * - * @param string - * A String containing an integer. + * @param string A String containing an integer. + * @param from The index to start parsing from * @return an int */ - public static int toInt(String string) + public static int toInt(String string,int from) { int val = 0; boolean started = false; boolean minus = false; - for (int i = 0; i < string.length(); i++) + for (int i = from; i < string.length(); i++) { char b = string.charAt(i); if (b <= ' ') @@ -657,7 +657,7 @@ public class StringUtil return minus?(-val):val; throw new NumberFormatException(string); } - + /** * Convert String to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown * From 43d7673c83402bf2ff57457988493bdb3a5b4a96 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 9 Jun 2014 16:30:56 +0200 Subject: [PATCH 034/269] fixed FCGI --- .../org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java index 0338a402f4a..39ef42b081c 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java @@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; @@ -76,8 +77,7 @@ public class HttpChannelOverFCGI extends HttpChannel String uri = path; if (query != null && query.length() > 0) uri += "?" + query; - startRequest(HttpMethod.fromString(method), method, ByteBuffer.wrap(uri.getBytes(StandardCharsets.UTF_8)), - HttpVersion.fromString(version)); + startRequest(method, new HttpURI(uri),HttpVersion.fromString(version)); for (HttpField fcgiField : fields) { From b38bae36f1fc7795b0ffcb638dd7b348d087f560 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 11:28:07 +0200 Subject: [PATCH 035/269] moved http/1.1 isms out of HttpChannel into HttpConnection --- .../authentication/FormAuthenticator.java | 3 +- .../org/eclipse/jetty/server/HttpChannel.java | 117 +------- .../jetty/server/HttpChannelOverHttp.java | 263 ++++++++++++++++++ .../eclipse/jetty/server/HttpConnection.java | 105 +------ .../jetty/server/ExtendedServerTest.java | 2 +- 5 files changed, 278 insertions(+), 212 deletions(-) create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java index dcfea4168c6..790d544536a 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java @@ -236,8 +236,7 @@ public class FormAuthenticator extends LoginAuthenticator //restore the original request's method on this request if (LOG.isDebugEnabled()) LOG.debug("Restoring original method {} for {} with method {}", method, juri,httpRequest.getMethod()); Request base_request = HttpChannel.getCurrentHttpChannel().getRequest(); - HttpMethod m = HttpMethod.fromString(method); - base_request.setMethod(m,m.asString()); + base_request.setMethod(method); } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index b8abcaec280..09e92923581 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -67,7 +67,7 @@ import org.eclipse.jetty.util.thread.Scheduler; * HttpTransport.completed(). * */ -public class HttpChannel implements HttpParser.RequestHandler, Runnable, HttpParser.ProxyHandler +public class HttpChannel implements HttpParser.RequestHandler, Runnable { private static final Logger LOG = Log.getLogger(HttpChannel.class); private static final ThreadLocal> __currentChannel = new ThreadLocal<>(); @@ -102,9 +102,6 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H private final Request _request; private final Response _response; private HttpVersion _version = HttpVersion.HTTP_1_1; - private boolean _expect = false; - private boolean _expect100Continue = false; - private boolean _expect102Processing = false; public HttpChannel(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) { @@ -201,32 +198,12 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H */ public void continue100(int available) throws IOException { - // If the client is expecting 100 CONTINUE, then send it now. - // TODO: consider using an AtomicBoolean ? - if (isExpecting100Continue()) - { - _expect100Continue = false; - - // is content missing? - if (available == 0) - { - if (_response.isCommitted()) - throw new IOException("Committed before 100 Continues"); - - // TODO: break this dependency with HttpGenerator - boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false); - if (!committed) - throw new IOException("Concurrent commit while trying to send 100-Continue"); - } - } + throw new UnsupportedOperationException(); } public void reset() { _committed.set(false); - _expect = false; - _expect100Continue = false; - _expect102Processing = false; _request.recycle(); _response.recycle(); } @@ -458,12 +435,12 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H public boolean isExpecting100Continue() { - return _expect100Continue; + return false; } public boolean isExpecting102Processing() { - return _expect102Processing; + return false; } @Override @@ -478,22 +455,9 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H ); } - @Override - public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort) - { - _request.setAttribute("PROXY", protocol); - _request.setServerName(sAddr); - _request.setServerPort(dPort); - _request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort)); - } - @Override public boolean startRequest(String method, HttpURI uri, HttpVersion version) { - _expect = false; - _expect100Continue = false; - _expect102Processing = false; - _request.setTimeStamp(System.currentTimeMillis()); _request.setMethod(method); @@ -515,7 +479,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H if (info == null) { - if( path==null && uri.getScheme()!=null &&uri.getHost()!=null) + if( path==null && uri.getScheme()!=null && uri.getHost()!=null) { info = "/"; _request.setRequestURI(""); @@ -526,8 +490,9 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H return true; } } + _request.setPathInfo(info); - _version = version == null ? HttpVersion.HTTP_0_9 : version; + _version = version; _request.setHttpVersion(_version); return false; @@ -544,46 +509,6 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H { switch (header) { - case EXPECT: - if (_version.getVersion()>=HttpVersion.HTTP_1_1.getVersion()) - { - HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); - switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) - { - case CONTINUE: - _expect100Continue = true; - break; - - case PROCESSING: - _expect102Processing = true; - break; - - default: - String[] values = value.split(","); - for (int i = 0; values != null && i < values.length; i++) - { - expect = HttpHeaderValue.CACHE.get(values[i].trim()); - if (expect == null) - _expect = true; - else - { - switch (expect) - { - case CONTINUE: - _expect100Continue = true; - break; - case PROCESSING: - _expect102Processing = true; - break; - default: - _expect = true; - } - } - } - } - } - break; - case CONTENT_TYPE: MimeTypes.Type mime = MimeTypes.CACHE.get(value); String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString(); @@ -614,31 +539,9 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H public boolean headerComplete() { _requests.incrementAndGet(); - switch (_version) - { - case HTTP_0_9: - break; - - case HTTP_1_0: - if (_configuration.getSendDateHeader()) - _response.getHttpFields().put(_connector.getServer().getDateField()); - break; - - case HTTP_1_1: - if (_configuration.getSendDateHeader()) - _response.getHttpFields().put(_connector.getServer().getDateField()); - - if (_expect) - { - badMessage(HttpStatus.EXPECTATION_FAILED_417,null); - return true; - } - - break; - - default: - throw new IllegalStateException(); - } + // TODO make this a better field for h2 hpack generation + if (_configuration.getSendDateHeader()) + _response.getHttpFields().put(_connector.getServer().getDateField()); return true; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java new file mode 100644 index 00000000000..bede165bcf9 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -0,0 +1,263 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpGenerator; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpHeaderValue; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpParser; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.io.EndPoint; + +/** + * A HttpChannel customized to be transported over the HTTP/1 protocol + */ +class HttpChannelOverHttp extends HttpChannel implements HttpParser.ProxyHandler +{ + /** + * + */ + private final HttpConnection _httpConnection; + private boolean _expect = false; + private boolean _expect100Continue = false; + private boolean _expect102Processing = false; + + public HttpChannelOverHttp(HttpConnection httpConnection, Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) + { + super(connector,config,endPoint,transport,input); + _httpConnection = httpConnection; + } + + @Override + public void reset() + { + super.reset(); + _expect = false; + _expect100Continue = false; + _expect102Processing = false; + } + + @Override + public boolean isExpecting100Continue() + { + return _expect100Continue; + } + + @Override + public boolean isExpecting102Processing() + { + return _expect102Processing; + } + + @Override + public boolean startRequest(String method, HttpURI uri, HttpVersion version) + { + _expect = false; + _expect100Continue = false; + _expect102Processing = false; + return super.startRequest(method,uri,version); + } + + @Override + public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort) + { + Request request = getRequest(); + request.setAttribute("PROXY", protocol); + request.setServerName(sAddr); + request.setServerPort(dPort); + request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort)); + } + + + @Override + public boolean parsedHeader(HttpField field) + { + HttpHeader header=field.getHeader(); + String value=field.getValue(); + if (getRequest().getHttpVersion().getVersion()==HttpVersion.HTTP_1_1.getVersion() && header == HttpHeader.EXPECT) + { + HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); + switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) + { + case CONTINUE: + _expect100Continue = true; + break; + + case PROCESSING: + _expect102Processing = true; + break; + + default: + String[] values = value.split(","); + for (int i = 0; values != null && i < values.length; i++) + { + expect = HttpHeaderValue.CACHE.get(values[i].trim()); + if (expect == null) + _expect = true; + else + { + switch (expect) + { + case CONTINUE: + _expect100Continue = true; + break; + case PROCESSING: + _expect102Processing = true; + break; + default: + _expect = true; + } + } + } + } + } + return super.parsedHeader(field); + } + + /** + * If the associated response has the Expect header set to 100 Continue, + * then accessing the input stream indicates that the handler/servlet + * is ready for the request body and thus a 100 Continue response is sent. + * + * @throws IOException if the InputStream cannot be created + */ + @Override + public void continue100(int available) throws IOException + { + // If the client is expecting 100 CONTINUE, then send it now. + // TODO: consider using an AtomicBoolean ? + if (isExpecting100Continue()) + { + _expect100Continue = false; + + // is content missing? + if (available == 0) + { + if (getResponse().isCommitted()) + throw new IOException("Committed before 100 Continues"); + + // TODO: break this dependency with HttpGenerator + boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false); + if (!committed) + throw new IOException("Concurrent commit while trying to send 100-Continue"); + } + } + } + + + @Override + public void earlyEOF() + { + // If we have no request yet, just close + if (getRequest().getMethod()==null) + _httpConnection.close(); + else + super.earlyEOF(); + } + + @Override + public boolean content(ByteBuffer item) + { + super.content(item); + return true; + } + + @Override + public void badMessage(int status, String reason) + { + _httpConnection._generator.setPersistent(false); + super.badMessage(status,reason); + } + + @Override + public boolean headerComplete() + { + boolean persistent; + HttpVersion version = getHttpVersion(); + + switch (version) + { + case HTTP_1_0: + { + persistent = getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); + if (!persistent) + persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); + if (persistent) + getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); + break; + } + + case HTTP_1_1: + { + if (_expect) + { + badMessage(HttpStatus.EXPECTATION_FAILED_417,null); + return true; + } + + persistent = !getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); + if (!persistent) + persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); + if (!persistent) + getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); + break; + } + + default: + { + throw new IllegalStateException(); + } + } + + if (!persistent) + _httpConnection._generator.setPersistent(false); + + return super.headerComplete(); + } + + @Override + protected void handleException(Throwable x) + { + _httpConnection._generator.setPersistent(false); + super.handleException(x); + } + + @Override + public void failed() + { + getEndPoint().shutdownOutput(); + } + + + @Override + public boolean messageComplete() + { + super.messageComplete(); + return false; + } +} \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 16cbbf93d6b..22a4326bd40 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -24,12 +24,9 @@ import java.util.concurrent.RejectedExecutionException; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator.ResponseInfo; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpHeaderValue; -import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.Connection; @@ -56,7 +53,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http private final HttpConfiguration _config; private final Connector _connector; private final ByteBufferPool _bufferPool; - private final HttpGenerator _generator; + final HttpGenerator _generator; private final HttpChannelOverHttp _channel; private final HttpParser _parser; private volatile ByteBuffer _requestBuffer = null; @@ -118,7 +115,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) { - return new HttpChannelOverHttp(_connector, _config, getEndPoint(), this, httpInput); + return new HttpChannelOverHttp(this, _connector, _config, getEndPoint(), this, httpInput); } protected HttpParser newHttpParser() @@ -447,102 +444,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http } - protected class HttpChannelOverHttp extends HttpChannel - { - public HttpChannelOverHttp(Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) - { - super(connector,config,endPoint,transport,input); - } - - @Override - public void earlyEOF() - { - // If we have no request yet, just close - if (getRequest().getMethod()==null) - close(); - else - super.earlyEOF(); - } - - @Override - public boolean content(ByteBuffer item) - { - super.content(item); - return true; - } - - @Override - public void badMessage(int status, String reason) - { - _generator.setPersistent(false); - super.badMessage(status,reason); - } - - @Override - public boolean headerComplete() - { - boolean persistent; - HttpVersion version = getHttpVersion(); - - switch (version) - { - case HTTP_0_9: - { - persistent = false; - break; - } - case HTTP_1_0: - { - persistent = getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); - if (!persistent) - persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); - if (persistent) - getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); - break; - } - case HTTP_1_1: - { - persistent = !getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); - if (!persistent) - persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); - if (!persistent) - getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); - break; - } - default: - { - throw new IllegalStateException(); - } - } - - if (!persistent) - _generator.setPersistent(false); - - return super.headerComplete(); - } - - @Override - protected void handleException(Throwable x) - { - _generator.setPersistent(false); - super.handleException(x); - } - - @Override - public void failed() - { - getEndPoint().shutdownOutput(); - } - - - @Override - public boolean messageComplete() - { - super.messageComplete(); - return false; - } - } - private class CommitCallback extends IteratingCallback { final ByteBuffer _content; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java index 9ddaaf56e15..7162da1d9c6 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java @@ -102,7 +102,7 @@ public class ExtendedServerTest extends HttpServerTestBase @Override protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) { - return new HttpChannelOverHttp(getConnector(), getHttpConfiguration(), getEndPoint(), this, httpInput) + return new HttpChannelOverHttp(this, getConnector(), getHttpConfiguration(), getEndPoint(), this, httpInput) { @Override public boolean startRequest(String method, HttpURI uri, HttpVersion version) From e0474108d09df92f69187427dff85841496fdc3d Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 08:56:34 +0200 Subject: [PATCH 036/269] Updated Frame inheritance. --- .../org/eclipse/jetty/http2/frames/DataFrame.java | 1 + .../java/org/eclipse/jetty/http2/frames/Frame.java | 12 ++++++++++++ .../org/eclipse/jetty/http2/frames/GoAwayFrame.java | 3 ++- .../org/eclipse/jetty/http2/frames/HeadersFrame.java | 3 ++- .../org/eclipse/jetty/http2/frames/PingFrame.java | 3 ++- .../eclipse/jetty/http2/frames/PriorityFrame.java | 3 ++- .../org/eclipse/jetty/http2/frames/ResetFrame.java | 3 ++- .../eclipse/jetty/http2/frames/SettingsFrame.java | 3 ++- .../jetty/http2/frames/WindowUpdateFrame.java | 3 ++- 9 files changed, 27 insertions(+), 7 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java index 9badd6fe9eb..e9e84cdc3dd 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -28,6 +28,7 @@ public class DataFrame extends Frame public DataFrame(int streamId, ByteBuffer data, boolean endStream) { + super(FrameType.DATA); this.streamId = streamId; this.data = data; this.endStream = endStream; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java index 0d3bf269ab5..7a58eb21841 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java @@ -22,4 +22,16 @@ public abstract class Frame { public static final int HEADER_LENGTH = 8; public static final int MAX_LENGTH = 0x3F_FF; + + private FrameType type; + + protected Frame(FrameType type) + { + this.type = type; + } + + public FrameType getType() + { + return type; + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java index d17d357de36..6615c0f6589 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java @@ -18,7 +18,7 @@ package org.eclipse.jetty.http2.frames; -public class GoAwayFrame +public class GoAwayFrame extends Frame { private final int lastStreamId; private final int error; @@ -26,6 +26,7 @@ public class GoAwayFrame public GoAwayFrame(int lastStreamId, int error, byte[] payload) { + super(FrameType.GO_AWAY); this.lastStreamId = lastStreamId; this.error = error; this.payload = payload; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java index eef67a45e64..dfb81246a4f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.http2.frames; import org.eclipse.jetty.http2.hpack.MetaData; -public class HeadersFrame +public class HeadersFrame extends Frame { private final int streamId; private final MetaData metaData; @@ -29,6 +29,7 @@ public class HeadersFrame public HeadersFrame(int streamId, MetaData metaData, PriorityFrame priority, boolean endStream) { + super(FrameType.HEADERS); this.streamId = streamId; this.metaData = metaData; this.priority = priority; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java index 575f63f0251..b56643cd4e4 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java @@ -18,13 +18,14 @@ package org.eclipse.jetty.http2.frames; -public class PingFrame +public class PingFrame extends Frame { private final byte[] payload; private final boolean reply; public PingFrame(byte[] payload, boolean reply) { + super(FrameType.PING); this.payload = payload; this.reply = reply; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java index e82a3c4be02..a8718874812 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java @@ -18,7 +18,7 @@ package org.eclipse.jetty.http2.frames; -public class PriorityFrame +public class PriorityFrame extends Frame { private final int streamId; private final int dependentStreamId; @@ -27,6 +27,7 @@ public class PriorityFrame public PriorityFrame(int streamId, int dependentStreamId, int weight, boolean exclusive) { + super(FrameType.PRIORITY); this.streamId = streamId; this.dependentStreamId = dependentStreamId; this.weight = weight; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java index 3fa1343dfec..55595e99f14 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java @@ -18,13 +18,14 @@ package org.eclipse.jetty.http2.frames; -public class ResetFrame +public class ResetFrame extends Frame { private final int streamId; private final int error; public ResetFrame(int streamId, int error) { + super(FrameType.RST_STREAM); this.streamId = streamId; this.error = error; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java index 5fe64b0a863..38cf1278771 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -20,13 +20,14 @@ package org.eclipse.jetty.http2.frames; import java.util.Map; -public class SettingsFrame +public class SettingsFrame extends Frame { private final Map settings; private final boolean reply; public SettingsFrame(Map settings, boolean reply) { + super(FrameType.SETTINGS); this.settings = settings; this.reply = reply; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java index 0ed4ac35dbe..ee0837ddc60 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java @@ -18,13 +18,14 @@ package org.eclipse.jetty.http2.frames; -public class WindowUpdateFrame +public class WindowUpdateFrame extends Frame { private final int streamId; private final int windowDelta; public WindowUpdateFrame(int streamId, int windowDelta) { + super(FrameType.WINDOW_UPDATE); this.streamId = streamId; this.windowDelta = windowDelta; } From 1d2e9da29cfb7fe9f5bc7abb0e914d939f8c8a5f Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 12:00:20 +0200 Subject: [PATCH 037/269] Clearing the buffer before returning it. --- .../src/main/java/org/eclipse/jetty/io/ByteBufferPool.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index 61c78fcb853..b9e9e0978b0 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -22,6 +22,8 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.util.BufferUtil; + /** *

A {@link ByteBuffer} pool.

*

Acquired buffers may be {@link #release(ByteBuffer) released} but they do not need to; @@ -67,6 +69,7 @@ public interface ByteBufferPool public ByteBuffer acquire(int capacity, boolean direct) { ByteBuffer buffer = byteBufferPool.acquire(capacity, direct); + BufferUtil.clearToFill(buffer); append(buffer, true); return buffer; } From ad034f4d54aa4d6ce04c6fe3da8e8f48f63b21e5 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 12:01:00 +0200 Subject: [PATCH 038/269] Reworked generation of frames (split into different generators) and sketched server-side handling and linking with channel. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 87 +++++- .../org/eclipse/jetty/http2/HTTP2Stream.java | 73 ++++- .../org/eclipse/jetty/http2/ISession.java | 28 ++ .../java/org/eclipse/jetty/http2/IStream.java | 3 + .../org/eclipse/jetty/http2/api/Stream.java | 10 +- .../org/eclipse/jetty/http2/frames/Flag.java | 1 + .../jetty/http2/generator/DataGenerator.java | 120 ++++++++ .../jetty/http2/generator/FrameGenerator.java | 48 +++ .../jetty/http2/generator/Generator.java | 287 +++--------------- .../http2/generator/GoAwayGenerator.java | 64 ++++ .../http2/generator/HeaderGenerator.java | 37 +++ .../http2/generator/HeadersGenerator.java | 92 ++++++ .../jetty/http2/generator/PingGenerator.java | 57 ++++ .../http2/generator/PriorityGenerator.java | 64 ++++ .../jetty/http2/generator/ResetGenerator.java | 57 ++++ .../http2/generator/SettingsGenerator.java | 59 ++++ .../generator/WindowUpdateGenerator.java | 59 ++++ .../http2/frames/DataGenerateParseTest.java | 12 +- .../http2/frames/GoAwayGenerateParseTest.java | 13 +- .../http2/frames/PingGenerateParseTest.java | 13 +- .../frames/PriorityGenerateParseTest.java | 13 +- .../http2/frames/ResetGenerateParseTest.java | 13 +- .../frames/SettingsGenerateParseTest.java | 18 +- .../frames/WindowUpdateGenerateParseTest.java | 13 +- jetty-http2/http2-server/pom.xml | 11 + .../http2/server/ByteBufferCallback.java | 62 ++++ .../server/HTTP2ServerConnectionFactory.java | 25 +- .../http2/server/HTTP2ServerSession.java | 16 +- .../http2/server/HttpChannelOverHTTP2.java | 83 ++++- .../http2/server/HttpInputOverHTTP2.java | 22 +- .../http2/server/HttpTransportOverHTTP2.java | 59 ++++ .../jetty/http2/server/HTTP2ServerTest.java | 128 ++++++++ 32 files changed, 1314 insertions(+), 333 deletions(-) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java create mode 100644 jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/ByteBufferCallback.java create mode 100644 jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index d82a8a724de..b0f5a8ec116 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -18,9 +18,14 @@ package org.eclipse.jetty.http2; -import org.eclipse.jetty.http2.api.Session; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; @@ -28,27 +33,38 @@ import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; +import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public abstract class HTTP2Session implements Session, Parser.Listener +public abstract class HTTP2Session implements ISession, Parser.Listener { private static final Logger LOG = Log.getLogger(HTTP2Session.class); + private final ConcurrentMap streams = new ConcurrentHashMap<>(); + private final Flusher flusher = new Flusher(); + private final EndPoint endPoint; + private final Generator generator; private final Listener listener; - public HTTP2Session(Session.Listener listener) + public HTTP2Session(EndPoint endPoint, Generator generator, Listener listener) { + this.endPoint = endPoint; + this.generator = generator; this.listener = listener; } @Override public boolean onData(DataFrame frame) { - return false; + IStream stream = streams.get(frame.getStreamId()); + return stream.process(frame); } @Override @@ -126,6 +142,18 @@ public abstract class HTTP2Session implements Session, Parser.Listener } + @Override + public void frame(Frame frame, Callback callback) + { + Generator.LeaseCallback lease = generator.generate(frame, callback); + flusher.flush(lease); + } + + protected IStream putIfAbsent(IStream stream) + { + return streams.putIfAbsent(stream.getId(), stream); + } + protected Stream.Listener notifyNewStream(Stream stream, HeadersFrame frame) { try @@ -138,4 +166,55 @@ public abstract class HTTP2Session implements Session, Parser.Listener return null; } } + + private class Flusher extends IteratingCallback + { + private final ArrayQueue queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH); + private Generator.LeaseCallback active; + + private void flush(Generator.LeaseCallback lease) + { + synchronized (queue) + { + queue.offer(lease); + } + iterate(); + } + + @Override + protected Action process() throws Exception + { + synchronized (queue) + { + active = queue.poll(); + } + if (active == null) + { + return Action.IDLE; + } + + List byteBuffers = active.getByteBuffers(); + endPoint.write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()])); + return Action.SCHEDULED; + } + + @Override + public void succeeded() + { + active.succeeded(); + super.succeeded(); + } + + @Override + public void failed(Throwable x) + { + active.failed(x); + super.failed(x); + } + + @Override + protected void completed() + { + } + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 2447ecf4162..1a5304f1d70 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -18,6 +18,10 @@ package org.eclipse.jetty.http2; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicReference; + import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -25,6 +29,15 @@ import org.eclipse.jetty.util.Callback; public class HTTP2Stream implements IStream { + private final AtomicReference> attributes = new AtomicReference<>(); + private final ISession session; + private Listener listener; + + public HTTP2Stream(ISession session) + { + this.session = session; + } + @Override public int getId() { @@ -40,13 +53,45 @@ public class HTTP2Stream implements IStream @Override public void headers(HeadersFrame frame, Callback callback) { - + session.frame(frame, callback); } @Override public void data(DataFrame frame, Callback callback) { + session.frame(frame, callback); + } + @Override + public Object getAttribute(String key) + { + return attributes().get(key); + } + + @Override + public void setAttribute(String key, Object value) + { + attributes().put(key, value); + } + + @Override + public Object removeAttribute(String key) + { + return attributes().remove(key); + } + + private ConcurrentMap attributes() + { + ConcurrentMap map = attributes.get(); + if (map == null) + { + map = new ConcurrentHashMap<>(); + if (!attributes.compareAndSet(null, map)) + { + map = attributes.get(); + } + } + return map; } @Override @@ -54,4 +99,30 @@ public class HTTP2Stream implements IStream { } + + @Override + public boolean process(DataFrame frame) + { + return notifyData(frame); + } + + protected boolean notifyData(DataFrame frame) + { + final Listener listener = this.listener; + listener.onData(this, frame, new Callback() + { + @Override + public void succeeded() + { + // TODO: notify flow control + } + + @Override + public void failed(Throwable x) + { + // TODO: bail out + } + }); + return true; + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java new file mode 100644 index 00000000000..905ccb30bd8 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -0,0 +1,28 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.util.Callback; + +public interface ISession extends Session +{ + public void frame(Frame frame, Callback callback); +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 9304f89137e..bc13bb9d268 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -19,8 +19,11 @@ package org.eclipse.jetty.http2; import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.DataFrame; public interface IStream extends Stream { public void setListener(Listener listener); + + public boolean process(DataFrame frame); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index 2dbc10cee63..78d696c6ea2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -32,11 +32,17 @@ public interface Stream public void data(DataFrame frame, Callback callback); + public Object getAttribute(String key); + + public void setAttribute(String key, Object value); + + public Object removeAttribute(String key); + // TODO: see SPDY's Stream public interface Listener { - public void onData(Stream stream, DataFrame frame); + public void onData(Stream stream, DataFrame frame, Callback callback); public void onFailure(Stream stream, Throwable x); @@ -45,7 +51,7 @@ public interface Stream public static class Adapter implements Listener { @Override - public void onData(Stream stream, DataFrame frame) + public void onData(Stream stream, DataFrame frame, Callback callback) { } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java index f29256241c6..0cbdc54ac26 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.frames; public interface Flag { + public static final int NONE = 0x00; public static final int END_STREAM = 0x01; public static final int ACK = END_STREAM; public static final int END_SEGMENT = 0x02; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java new file mode 100644 index 00000000000..3ef4497b3ed --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -0,0 +1,120 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; + +public class DataGenerator extends FrameGenerator +{ + public DataGenerator(HeaderGenerator headerGenerator) + { + super(headerGenerator); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + { + DataFrame dataFrame = (DataFrame)frame; + generateData(lease, dataFrame.getStreamId(), dataFrame.getData(), dataFrame.isEndStream(), false, null); + } + + public void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, boolean compress, byte[] paddingBytes) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; + // Leave space for at least one byte of content. + if (paddingLength > Frame.MAX_LENGTH - 3) + throw new IllegalArgumentException("Invalid padding length: " + paddingLength); + if (compress) + throw new IllegalArgumentException("Data compression not supported"); + + int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; + + int dataLength = data.remaining(); + + // Can we fit just one frame ? + if (dataLength + extraPaddingBytes + paddingLength <= Frame.MAX_LENGTH) + { + generateData(lease, streamId, data, last, compress, extraPaddingBytes, paddingBytes); + } + else + { + int dataBytesPerFrame = Frame.MAX_LENGTH - extraPaddingBytes - paddingLength; + int frames = dataLength / dataBytesPerFrame; + if (frames * dataBytesPerFrame != dataLength) + { + ++frames; + } + int limit = data.limit(); + for (int i = 1; i <= frames; ++i) + { + data.limit(Math.min(dataBytesPerFrame * i, limit)); + ByteBuffer slice = data.slice(); + data.position(data.limit()); + generateData(lease, streamId, slice, i == frames && last, compress, extraPaddingBytes, paddingBytes); + } + } + } + + private void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, boolean compress, int extraPaddingBytes, byte[] paddingBytes) + { + int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; + int length = extraPaddingBytes + data.remaining() + paddingLength; + + int flags = Flag.NONE; + if (last) + flags |= Flag.END_STREAM; + if (extraPaddingBytes > 0) + flags |= Flag.PADDING_LOW; + if (extraPaddingBytes > 1) + flags |= Flag.PADDING_HIGH; + if (compress) + flags |= Flag.COMPRESS; + + ByteBuffer header = generateHeader(lease, FrameType.DATA, Frame.HEADER_LENGTH + extraPaddingBytes, length, flags, streamId); + + if (extraPaddingBytes == 2) + { + header.putShort((short)paddingLength); + } + else if (extraPaddingBytes == 1) + { + header.put((byte)paddingLength); + } + + BufferUtil.flipToFlush(header, 0); + lease.append(header, true); + + lease.append(data, false); + + if (paddingBytes != null) + { + lease.append(ByteBuffer.wrap(paddingBytes), false); + } + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java new file mode 100644 index 00000000000..e8039de130c --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java @@ -0,0 +1,48 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.Callback; + +public abstract class FrameGenerator +{ + private final HeaderGenerator headerGenerator; + + protected FrameGenerator(HeaderGenerator headerGenerator) + { + this.headerGenerator = headerGenerator; + } + + public abstract void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback); + + protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int length, int flags, int streamId) + { + return generateHeader(lease, frameType, Frame.HEADER_LENGTH + length, length, flags, streamId); + } + + protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int capacity, int length, int flags, int streamId) + { + return headerGenerator.generate(lease, frameType, capacity, length, flags, streamId); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 09373568d77..dda42dc0065 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -18,284 +18,69 @@ package org.eclipse.jetty.http2.generator; -import java.nio.ByteBuffer; -import java.util.Map; - -import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; public class Generator { private final ByteBufferPool byteBufferPool; - private final HpackEncoder encoder; + private final FrameGenerator[] generators; public Generator(ByteBufferPool byteBufferPool) { this.byteBufferPool = byteBufferPool; - this.encoder = new HpackEncoder(); + + HeaderGenerator headerGenerator = new HeaderGenerator(); + HpackEncoder encoder = new HpackEncoder(); + + this.generators = new FrameGenerator[FrameType.values().length]; + this.generators[FrameType.DATA.getType()] = new DataGenerator(headerGenerator); + this.generators[FrameType.HEADERS.getType()] = new HeadersGenerator(headerGenerator, encoder); + this.generators[FrameType.PRIORITY.getType()] = new PriorityGenerator(headerGenerator); + this.generators[FrameType.RST_STREAM.getType()] = new ResetGenerator(headerGenerator); + this.generators[FrameType.SETTINGS.getType()] = new SettingsGenerator(headerGenerator); + this.generators[FrameType.PUSH_PROMISE.getType()] = null; // TODO + this.generators[FrameType.PING.getType()] = new PingGenerator(headerGenerator); + this.generators[FrameType.GO_AWAY.getType()] = new GoAwayGenerator(headerGenerator); + this.generators[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateGenerator(headerGenerator); + this.generators[FrameType.CONTINUATION.getType()] = null; // TODO + this.generators[FrameType.ALTSVC.getType()] = null; // TODO + this.generators[FrameType.BLOCKED.getType()] = null; // TODO + } - public ByteBufferPool.Lease generateData(int streamId, ByteBuffer data, boolean last, boolean compress, byte[] paddingBytes) + public LeaseCallback generate(Frame frame, Callback callback) { - if (streamId < 0) - throw new IllegalArgumentException("Invalid stream id: " + streamId); - int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; - // Leave space for at least one byte of content. - if (paddingLength > Frame.MAX_LENGTH - 3) - throw new IllegalArgumentException("Invalid padding length: " + paddingLength); - - int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; - - // TODO: here we should compress the data, and then reason on the data length ! - - int dataLength = data.remaining(); - - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - - // Can we fit just one frame ? - if (dataLength + extraPaddingBytes + paddingLength <= Frame.MAX_LENGTH) - { - generateData(lease, streamId, data, last, compress, extraPaddingBytes, paddingBytes); - } - else - { - int dataBytesPerFrame = Frame.MAX_LENGTH - extraPaddingBytes - paddingLength; - int frames = dataLength / dataBytesPerFrame; - if (frames * dataBytesPerFrame != dataLength) - { - ++frames; - } - int limit = data.limit(); - for (int i = 1; i <= frames; ++i) - { - data.limit(Math.min(dataBytesPerFrame * i, limit)); - ByteBuffer slice = data.slice(); - data.position(data.limit()); - generateData(lease, streamId, slice, i == frames && last, compress, extraPaddingBytes, paddingBytes); - } - } + LeaseCallback lease = new LeaseCallback(byteBufferPool, callback); + generators[frame.getType().getType()].generate(lease, frame, callback); return lease; } - public ByteBufferPool.Lease generateHeaders(int streamId, MetaData metaData, boolean contentFollows, byte[] paddingBytes) + public static class LeaseCallback extends ByteBufferPool.Lease implements Callback { - if (streamId < 0) - throw new IllegalArgumentException("Invalid stream id: " + streamId); - int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; - // Leave space for at least one byte of content. - if (paddingLength > Frame.MAX_LENGTH - 3) - throw new IllegalArgumentException("Invalid padding length: " + paddingLength); + private final Callback callback; - int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; - - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - - encoder.encode(metaData, lease); - - long hpackLength = lease.getTotalLength(); - - long length = extraPaddingBytes + hpackLength + paddingLength; - if (length > Frame.MAX_LENGTH) - throw new IllegalArgumentException("Invalid headers, too big"); - - int flags = Flag.END_HEADERS; - if (!contentFollows) - flags |= Flag.END_STREAM; - if (extraPaddingBytes > 0) - flags |= Flag.PADDING_LOW; - if (extraPaddingBytes > 1) - flags |= Flag.PADDING_HIGH; - - ByteBuffer header = generateHeader(FrameType.HEADERS, Frame.HEADER_LENGTH + extraPaddingBytes, (int)length, flags, streamId); - - if (extraPaddingBytes == 2) - header.putShort((short)paddingLength); - else if (extraPaddingBytes == 1) - header.put((byte)paddingLength); - - BufferUtil.flipToFlush(header, 0); - lease.prepend(header, true); - - if (paddingBytes != null) + public LeaseCallback(ByteBufferPool byteBufferPool, Callback callback) { - lease.append(ByteBuffer.wrap(paddingBytes), false); + super(byteBufferPool); + this.callback = callback; } - return lease; - } - - public ByteBufferPool.Lease generatePriority(int streamId, int dependentStreamId, int weight, boolean exclusive) - { - if (streamId < 0) - throw new IllegalArgumentException("Invalid stream id: " + streamId); - if (dependentStreamId < 0) - throw new IllegalArgumentException("Invalid dependent stream id: " + dependentStreamId); - - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - - ByteBuffer header = generateHeader(FrameType.PRIORITY, 5, 0, dependentStreamId); - - if (exclusive) - streamId |= 0x80_00_00_00; - - header.putInt(streamId); - - header.put((byte)weight); - - BufferUtil.flipToFlush(header, 0); - lease.append(header, true); - - return lease; - } - - public ByteBufferPool.Lease generateReset(int streamId, int error) - { - if (streamId < 0) - throw new IllegalArgumentException("Invalid stream id: " + streamId); - - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - - ByteBuffer header = generateHeader(FrameType.RST_STREAM, 4, 0, streamId); - - header.putInt(error); - - BufferUtil.flipToFlush(header, 0); - lease.append(header, true); - - return lease; - } - - public ByteBufferPool.Lease generateSettings(Map settings, boolean reply) - { - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - - ByteBuffer header = generateHeader(FrameType.SETTINGS, 5 * settings.size(), reply ? 0x01 : 0x00, 0); - - for (Map.Entry entry : settings.entrySet()) + @Override + public void succeeded() { - header.put(entry.getKey().byteValue()); - header.putInt(entry.getValue()); + recycle(); + callback.succeeded(); } - BufferUtil.flipToFlush(header, 0); - lease.append(header, true); - - return lease; - } - - public ByteBufferPool.Lease generatePing(byte[] payload, boolean reply) - { - if (payload.length != 8) - throw new IllegalArgumentException("Invalid payload length: " + payload.length); - - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - - ByteBuffer header = generateHeader(FrameType.PING, 8, reply ? 0x01 : 0x00, 0); - - header.put(payload); - - BufferUtil.flipToFlush(header, 0); - lease.append(header, true); - - return lease; - } - - public ByteBufferPool.Lease generateGoAway(int lastStreamId, int error, byte[] payload) - { - if (lastStreamId < 0) - throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId); - - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - - int length = 4 + 4 + (payload != null ? payload.length : 0); - ByteBuffer header = generateHeader(FrameType.GO_AWAY, length, 0, 0); - - header.putInt(lastStreamId); - header.putInt(error); - - if (payload != null) + @Override + public void failed(Throwable x) { - header.put(payload); + recycle(); + callback.failed(x); } - - BufferUtil.flipToFlush(header, 0); - lease.append(header, true); - - return lease; - } - - public ByteBufferPool.Lease generateWindowUpdate(int streamId, int windowUpdate) - { - if (streamId < 0) - throw new IllegalArgumentException("Invalid stream id: " + streamId); - if (windowUpdate < 0) - throw new IllegalArgumentException("Invalid window update: " + windowUpdate); - - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - - ByteBuffer header = generateHeader(FrameType.WINDOW_UPDATE, 4, 0, streamId); - - header.putInt(windowUpdate); - - BufferUtil.flipToFlush(header, 0); - lease.append(header, true); - - return lease; - } - - private void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, boolean compress, int extraPaddingBytes, byte[] paddingBytes) - { - int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; - int length = extraPaddingBytes + data.remaining() + paddingLength; - - int flags = 0; - if (last) - flags |= Flag.END_STREAM; - if (extraPaddingBytes > 0) - flags |= Flag.PADDING_LOW; - if (extraPaddingBytes > 1) - flags |= Flag.PADDING_HIGH; - if (compress) - flags |= Flag.COMPRESS; - - ByteBuffer header = generateHeader(FrameType.DATA, Frame.HEADER_LENGTH + extraPaddingBytes, length, flags, streamId); - - if (extraPaddingBytes == 2) - header.putShort((short)paddingLength); - else if (extraPaddingBytes == 1) - header.put((byte)paddingLength); - - BufferUtil.flipToFlush(header, 0); - lease.append(header, true); - - lease.append(data, false); - - if (paddingBytes != null) - { - lease.append(ByteBuffer.wrap(paddingBytes), false); - } - } - - private ByteBuffer generateHeader(FrameType frameType, int length, int flags, int streamId) - { - return generateHeader(frameType, Frame.HEADER_LENGTH + length, length, flags, streamId); - } - - private ByteBuffer generateHeader(FrameType frameType, int capacity, int length, int flags, int streamId) - { - ByteBuffer header = byteBufferPool.acquire(capacity, true); - BufferUtil.clearToFill(header); - - header.putShort((short)length); - header.put((byte)frameType.getType()); - header.put((byte)flags); - header.putInt(streamId); - - return header; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java new file mode 100644 index 00000000000..6bb93d3336a --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -0,0 +1,64 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.GoAwayFrame; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; + +public class GoAwayGenerator extends FrameGenerator +{ + public GoAwayGenerator(HeaderGenerator headerGenerator) + { + super(headerGenerator); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + { + GoAwayFrame goAwayFrame = (GoAwayFrame)frame; + generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), null); + } + + public void generateGoAway(ByteBufferPool.Lease lease, int lastStreamId, int error, byte[] payload) + { + if (lastStreamId < 0) + throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId); + + int length = 4 + 4 + (payload != null ? payload.length : 0); + ByteBuffer header = generateHeader(lease, FrameType.GO_AWAY, length, Flag.NONE, 0); + + header.putInt(lastStreamId); + header.putInt(error); + + if (payload != null) + { + header.put(payload); + } + + BufferUtil.flipToFlush(header, 0); + lease.append(header, true); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java new file mode 100644 index 00000000000..5c74d58e118 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java @@ -0,0 +1,37 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.io.ByteBufferPool; + +public class HeaderGenerator +{ + public ByteBuffer generate(ByteBufferPool.Lease lease, FrameType frameType, int capacity, int length, int flags, int streamId) + { + ByteBuffer header = lease.acquire(capacity, true); + header.putShort((short)length); + header.put((byte)frameType.getType()); + header.put((byte)flags); + header.putInt(streamId); + return header; + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java new file mode 100644 index 00000000000..7c1accb284d --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -0,0 +1,92 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.hpack.HpackEncoder; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; + +public class HeadersGenerator extends FrameGenerator +{ + private final HpackEncoder encoder; + + public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder) + { + super(headerGenerator); + this.encoder = encoder; + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + { + HeadersFrame headersFrame = (HeadersFrame)frame; + generate(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream(), null); + } + + private void generate(ByteBufferPool.Lease lease, int streamId, MetaData metaData, boolean contentFollows, byte[] paddingBytes) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; + // Leave space for at least one byte of content. + if (paddingLength > Frame.MAX_LENGTH - 3) + throw new IllegalArgumentException("Invalid padding length: " + paddingLength); + + int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; + + encoder.encode(metaData, lease); + + long hpackLength = lease.getTotalLength(); + + long length = extraPaddingBytes + hpackLength + paddingLength; + if (length > Frame.MAX_LENGTH) + throw new IllegalArgumentException("Invalid headers, too big"); + + int flags = Flag.END_HEADERS; + if (!contentFollows) + flags |= Flag.END_STREAM; + if (extraPaddingBytes > 0) + flags |= Flag.PADDING_LOW; + if (extraPaddingBytes > 1) + flags |= Flag.PADDING_HIGH; + + ByteBuffer header = generateHeader(lease, FrameType.HEADERS, Frame.HEADER_LENGTH + extraPaddingBytes, (int)length, flags, streamId); + + if (extraPaddingBytes == 2) + header.putShort((short)paddingLength); + else if (extraPaddingBytes == 1) + header.put((byte)paddingLength); + + BufferUtil.flipToFlush(header, 0); + lease.prepend(header, true); + + if (paddingBytes != null) + { + lease.append(ByteBuffer.wrap(paddingBytes), false); + } + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java new file mode 100644 index 00000000000..940bb896953 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java @@ -0,0 +1,57 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.PingFrame; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; + +public class PingGenerator extends FrameGenerator +{ + public PingGenerator(HeaderGenerator headerGenerator) + { + super(headerGenerator); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + { + PingFrame pingFrame = (PingFrame)frame; + generatePing(lease, pingFrame.getPayload(), pingFrame.isReply()); + } + + public void generatePing(ByteBufferPool.Lease lease, byte[] payload, boolean reply) + { + if (payload.length != 8) + throw new IllegalArgumentException("Invalid payload length: " + payload.length); + + ByteBuffer header = generateHeader(lease, FrameType.PING, 8, reply ? Flag.ACK : Flag.NONE, 0); + + header.put(payload); + + BufferUtil.flipToFlush(header, 0); + lease.append(header, true); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java new file mode 100644 index 00000000000..8364a55ddaf --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java @@ -0,0 +1,64 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.PriorityFrame; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; + +public class PriorityGenerator extends FrameGenerator +{ + public PriorityGenerator(HeaderGenerator headerGenerator) + { + super(headerGenerator); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + { + PriorityFrame priorityFrame = (PriorityFrame)frame; + generatePriority(lease, priorityFrame.getStreamId(), priorityFrame.getDependentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive()); + } + + public void generatePriority(ByteBufferPool.Lease lease, int streamId, int dependentStreamId, int weight, boolean exclusive) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + if (dependentStreamId < 0) + throw new IllegalArgumentException("Invalid dependent stream id: " + dependentStreamId); + + ByteBuffer header = generateHeader(lease, FrameType.PRIORITY, 5, Flag.NONE, dependentStreamId); + + if (exclusive) + streamId |= 0x80_00_00_00; + + header.putInt(streamId); + + header.put((byte)weight); + + BufferUtil.flipToFlush(header, 0); + lease.append(header, true); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java new file mode 100644 index 00000000000..48b792e0074 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java @@ -0,0 +1,57 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; + +public class ResetGenerator extends FrameGenerator +{ + public ResetGenerator(HeaderGenerator headerGenerator) + { + super(headerGenerator); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + { + ResetFrame resetFrame = (ResetFrame)frame; + generateReset(lease, resetFrame.getStreamId(), resetFrame.getError()); + } + + public void generateReset(ByteBufferPool.Lease lease, int streamId, int error) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + + ByteBuffer header = generateHeader(lease, FrameType.RST_STREAM, 4, Flag.NONE, streamId); + + header.putInt(error); + + BufferUtil.flipToFlush(header, 0); + lease.append(header, true); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java new file mode 100644 index 00000000000..77f483b3e4e --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -0,0 +1,59 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; +import java.util.Map; + +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; + +public class SettingsGenerator extends FrameGenerator +{ + public SettingsGenerator(HeaderGenerator headerGenerator) + { + super(headerGenerator); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + { + SettingsFrame settingsFrame = (SettingsFrame)frame; + generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply()); + } + + public void generateSettings(ByteBufferPool.Lease lease, Map settings, boolean reply) + { + ByteBuffer header = generateHeader(lease, FrameType.SETTINGS, 5 * settings.size(), reply ? Flag.ACK : Flag.NONE, 0); + + for (Map.Entry entry : settings.entrySet()) + { + header.put(entry.getKey().byteValue()); + header.putInt(entry.getValue()); + } + + BufferUtil.flipToFlush(header, 0); + lease.append(header, true); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java new file mode 100644 index 00000000000..099930371ee --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java @@ -0,0 +1,59 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; + +public class WindowUpdateGenerator extends FrameGenerator +{ + public WindowUpdateGenerator(HeaderGenerator headerGenerator) + { + super(headerGenerator); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + { + WindowUpdateFrame windowUpdateFrame = (WindowUpdateFrame)frame; + generateWindowUpdate(lease, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta()); + } + + public void generateWindowUpdate(ByteBufferPool.Lease lease, int streamId, int windowUpdate) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + if (windowUpdate < 0) + throw new IllegalArgumentException("Invalid window update: " + windowUpdate); + + ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flag.NONE, streamId); + + header.putInt(windowUpdate); + + BufferUtil.flipToFlush(header, 0); + lease.append(header, true); + } +} diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 44736009a6a..23c1981eff0 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -23,7 +23,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.generator.DataGenerator; +import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -132,7 +133,7 @@ public class DataGenerateParseTest private List testGenerateParse(int paddingLength, ByteBuffer... data) { - Generator generator = new Generator(byteBufferPool); + DataGenerator generator = new DataGenerator(new HeaderGenerator()); // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); @@ -141,7 +142,7 @@ public class DataGenerateParseTest ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); for (int j = 1; j <= data.length; ++j) { - lease = lease.merge(generator.generateData(13, data[j - 1].slice(), j == data.length, false, new byte[paddingLength])); + generator.generateData(lease, 13, data[j - 1].slice(), j == data.length, false, new byte[paddingLength]); } Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() @@ -167,9 +168,10 @@ public class DataGenerateParseTest @Test public void testGenerateParseOneByteAtATime() { - Generator generator = new Generator(byteBufferPool); + DataGenerator generator = new DataGenerator(new HeaderGenerator()); - ByteBufferPool.Lease lease = generator.generateData(13, ByteBuffer.wrap(largeContent).slice(), true, false, new byte[1024]); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateData(lease, 13, ByteBuffer.wrap(largeContent).slice(), true, false, new byte[1024]); final List frames = new ArrayList<>(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java index b98115249ff..e152dbf3753 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java @@ -23,7 +23,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.generator.GoAwayGenerator; +import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -37,7 +38,7 @@ public class GoAwayGenerateParseTest @Test public void testGenerateParse() throws Exception { - Generator generator = new Generator(byteBufferPool); + GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator()); int lastStreamId = 13; int error = 17; @@ -46,7 +47,8 @@ public class GoAwayGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - ByteBufferPool.Lease lease = generator.generateGoAway(lastStreamId, error, null); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateGoAway(lease, lastStreamId, error, null); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -77,7 +79,7 @@ public class GoAwayGenerateParseTest @Test public void testGenerateParseOneByteAtATime() throws Exception { - Generator generator = new Generator(byteBufferPool); + GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator()); int lastStreamId = 13; int error = 17; @@ -85,7 +87,8 @@ public class GoAwayGenerateParseTest new Random().nextBytes(payload); final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = generator.generateGoAway(lastStreamId, error, payload); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateGoAway(lease, lastStreamId, error, payload); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java index 56595f93458..b0ecb82b544 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -23,7 +23,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.generator.HeaderGenerator; +import org.eclipse.jetty.http2.generator.PingGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -37,7 +38,7 @@ public class PingGenerateParseTest @Test public void testGenerateParse() throws Exception { - Generator generator = new Generator(byteBufferPool); + PingGenerator generator = new PingGenerator(new HeaderGenerator()); byte[] payload = new byte[8]; new Random().nextBytes(payload); @@ -46,7 +47,8 @@ public class PingGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - ByteBufferPool.Lease lease = generator.generatePing(payload, true); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePing(lease, payload, true); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -76,13 +78,14 @@ public class PingGenerateParseTest @Test public void testGenerateParseOneByteAtATime() throws Exception { - Generator generator = new Generator(byteBufferPool); + PingGenerator generator = new PingGenerator(new HeaderGenerator()); byte[] payload = new byte[8]; new Random().nextBytes(payload); final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = generator.generatePing(payload, true); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePing(lease, payload, true); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index 33b86c8edfe..b6a93f55647 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -22,7 +22,8 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.generator.HeaderGenerator; +import org.eclipse.jetty.http2.generator.PriorityGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -36,7 +37,7 @@ public class PriorityGenerateParseTest @Test public void testGenerateParse() throws Exception { - Generator generator = new Generator(byteBufferPool); + PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator()); int streamId = 13; int dependentStreamId = 17; @@ -47,7 +48,8 @@ public class PriorityGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - ByteBufferPool.Lease lease = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePriority(lease, streamId, dependentStreamId, weight, exclusive); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -79,7 +81,7 @@ public class PriorityGenerateParseTest @Test public void testGenerateParseOneByteAtATime() throws Exception { - Generator generator = new Generator(byteBufferPool); + PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator()); int streamId = 13; int dependentStreamId = 17; @@ -87,7 +89,8 @@ public class PriorityGenerateParseTest boolean exclusive = true; final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = generator.generatePriority(streamId, dependentStreamId, weight, exclusive); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePriority(lease, streamId, dependentStreamId, weight, exclusive); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index 3bf0e44c6bc..05cc77661d5 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -22,7 +22,8 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.generator.HeaderGenerator; +import org.eclipse.jetty.http2.generator.ResetGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -36,7 +37,7 @@ public class ResetGenerateParseTest @Test public void testGenerateParse() throws Exception { - Generator generator = new Generator(byteBufferPool); + ResetGenerator generator = new ResetGenerator(new HeaderGenerator()); int streamId = 13; int error = 17; @@ -45,7 +46,8 @@ public class ResetGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - ByteBufferPool.Lease lease = generator.generateReset(streamId, error); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateReset(lease, streamId, error); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -75,13 +77,14 @@ public class ResetGenerateParseTest @Test public void testGenerateParseOneByteAtATime() throws Exception { - Generator generator = new Generator(byteBufferPool); + ResetGenerator generator = new ResetGenerator(new HeaderGenerator()); int streamId = 13; int error = 17; final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = generator.generateReset(streamId, error); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateReset(lease, streamId, error); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index 644ac83eb82..381a1ddf664 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -26,7 +26,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.generator.HeaderGenerator; +import org.eclipse.jetty.http2.generator.SettingsGenerator; import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; @@ -69,13 +70,14 @@ public class SettingsGenerateParseTest private List testGenerateParse(Map settings) { - Generator generator = new Generator(byteBufferPool); + SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - ByteBufferPool.Lease lease = generator.generateSettings(settings, true); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateSettings(lease, settings, true); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -102,10 +104,11 @@ public class SettingsGenerateParseTest @Test public void testGenerateParseInvalidSettings() throws Exception { - Generator generator = new Generator(byteBufferPool); + SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); Map settings1 = new HashMap<>(); settings1.put(13, 17); - ByteBufferPool.Lease lease = generator.generateSettings(settings1, true); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateSettings(lease, settings1, true); // Modify the length of the frame to make it invalid ByteBuffer bytes = lease.getByteBuffers().get(0); bytes.putShort(0, (short)(bytes.getShort(0) - 1)); @@ -134,7 +137,7 @@ public class SettingsGenerateParseTest @Test public void testGenerateParseOneByteAtATime() throws Exception { - Generator generator = new Generator(byteBufferPool); + SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); Map settings1 = new HashMap<>(); int key = 13; @@ -142,7 +145,8 @@ public class SettingsGenerateParseTest settings1.put(key, value); final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = generator.generateSettings(settings1, true); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateSettings(lease, settings1, true); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java index c3c5168f55a..ea7095628b8 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java @@ -22,7 +22,8 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.generator.HeaderGenerator; +import org.eclipse.jetty.http2.generator.WindowUpdateGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -36,7 +37,7 @@ public class WindowUpdateGenerateParseTest @Test public void testGenerateParse() throws Exception { - Generator generator = new Generator(byteBufferPool); + WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator()); int streamId = 13; int windowUpdate = 17; @@ -45,7 +46,8 @@ public class WindowUpdateGenerateParseTest final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { - ByteBufferPool.Lease lease = generator.generateWindowUpdate(streamId, windowUpdate); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateWindowUpdate(lease, streamId, windowUpdate); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -75,13 +77,14 @@ public class WindowUpdateGenerateParseTest @Test public void testGenerateParseOneByteAtATime() throws Exception { - Generator generator = new Generator(byteBufferPool); + WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator()); int streamId = 13; int windowUpdate = 17; final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = generator.generateWindowUpdate(streamId, windowUpdate); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateWindowUpdate(lease, streamId, windowUpdate); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index d0bd72672c4..814ad7fd6ca 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -54,6 +54,17 @@ jetty-server ${project.version} + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + org.eclipse.jetty + jetty-servlet + ${project.version} + test + diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/ByteBufferCallback.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/ByteBufferCallback.java new file mode 100644 index 00000000000..ac2d949c21b --- /dev/null +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/ByteBufferCallback.java @@ -0,0 +1,62 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.Callback; + +public class ByteBufferCallback implements Callback +{ + private final ByteBufferPool byteBufferPool; + private final ByteBuffer buffer; + private final Callback callback; + + public ByteBufferCallback(ByteBufferPool byteBufferPool, ByteBuffer buffer, Callback callback) + { + this.byteBufferPool = byteBufferPool; + this.buffer = buffer; + this.callback = callback; + } + + public ByteBuffer getByteBuffer() + { + return buffer; + } + + @Override + public void succeeded() + { + recycle(); + callback.succeeded(); + } + + @Override + public void failed(Throwable x) + { + recycle(); + callback.failed(x); + } + + private void recycle() + { + byteBufferPool.release(buffer); + } +} diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index d2ef7e271eb..145584b353e 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -25,18 +25,22 @@ import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.AbstractConnectionFactory; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory { private static final Logger LOG = Log.getLogger(HTTP2ServerConnectionFactory.class); + private static final String CHANNEL_ATTRIBUTE = HttpChannelOverHTTP2.class.getName(); + private final HttpConfiguration httpConfiguration; public HTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration) @@ -50,7 +54,8 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory { Session.Listener listener = new HTTPServerSessionListener(connector, httpConfiguration, endPoint); - HTTP2Session session = new HTTP2ServerSession(listener); + Generator generator = new Generator(connector.getByteBufferPool()); + HTTP2Session session = new HTTP2ServerSession(endPoint, generator, listener); Parser parser = new Parser(connector.getByteBufferPool(), session); HTTP2Connection connection = new HTTP2Connection(connector.getByteBufferPool(), connector.getExecutor(), @@ -67,7 +72,6 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory public HTTPServerSessionListener(Connector connector, HttpConfiguration httpConfiguration, EndPoint endPoint) { - this.connector = connector; this.httpConfiguration = httpConfiguration; this.endPoint = endPoint; @@ -81,29 +85,24 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2(); HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input); - // TODO: link channel to stream. + stream.setAttribute(CHANNEL_ATTRIBUTE, channel); -// if (frame.getMetaData().isEmpty()) -// { - // TODO: abort. -// return null; -// } - - channel.requestStart(frame); + channel.requestHeaders(frame); return frame.isEndStream() ? null : this; } @Override - public void onData(Stream stream, DataFrame frame) + public void onData(Stream stream, DataFrame frame, Callback callback) { - + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(CHANNEL_ATTRIBUTE); + channel.requestContent(frame, callback); } @Override public void onFailure(Stream stream, Throwable x) { - + // TODO } } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index afaa79bb5b4..a0a3f3f735d 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -18,22 +18,19 @@ package org.eclipse.jetty.http2.server; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.HTTP2Stream; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.io.EndPoint; public class HTTP2ServerSession extends HTTP2Session { - private final ConcurrentMap streams = new ConcurrentHashMap<>(); - - public HTTP2ServerSession(Listener listener) + public HTTP2ServerSession(EndPoint endPoint, Generator generator, Listener listener) { - super(listener); + super(endPoint, generator, listener); } @Override @@ -41,9 +38,10 @@ public class HTTP2ServerSession extends HTTP2Session { // TODO: handle max concurrent streams // TODO: handle duplicate streams + // TODO: handle empty headers - IStream stream = new HTTP2Stream(); - IStream existing = streams.putIfAbsent(stream.getId(), stream); + IStream stream = new HTTP2Stream(this); + IStream existing = putIfAbsent(stream); if (existing == null) { Stream.Listener listener = notifyNewStream(stream, frame); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 5be1a9beb3f..f64005f2697 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -19,11 +19,16 @@ package org.eclipse.jetty.http2.server; import java.nio.ByteBuffer; +import java.util.List; -import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpChannel; @@ -31,23 +36,83 @@ import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpInput; import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; -public class HttpChannelOverHTTP2 extends HttpChannel +public class HttpChannelOverHTTP2 extends HttpChannel { - public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) + public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) { super(connector, configuration, endPoint, transport, input); } - public void requestStart(HeadersFrame frame) + public void requestHeaders(HeadersFrame frame) { - // TODO: extract method, etc. - String method = null; - HttpURI uri = new HttpURI("/foo/bar"); - HttpVersion version = null; + MetaData metaData = frame.getMetaData(); + if (!metaData.isRequest()) + { + badMessage(400, null); + return; + } + + MetaData.Request requestMetaData = (MetaData.Request)metaData; + + String method = requestMetaData.getMethod(); + HttpURI uri = new HttpURI(requestMetaData.getPath()); + HttpVersion version = HttpVersion.HTTP_2_0; startRequest(method, uri, version); - // TODO: See SPDY's + HttpScheme scheme = requestMetaData.getScheme(); + if (scheme != null) + { + getRequest().setScheme(scheme.asString()); + } + + parsedHostHeader(requestMetaData.getHost(), requestMetaData.getPort()); + + List fields = requestMetaData.getFields(); + for (int i = 0; i < fields.size(); ++i) + { + HttpField field = fields.get(i); + parsedHeader(field); + } + + headerComplete(); + + if (frame.isEndStream()) + { + messageComplete(); + } + + // TODO: pending refactoring of HttpChannel API. + // Here we "cheat", knowing that headerComplete() will always return true + // and that content() and messageComplete() will always return false. + // This is the only place where we process the channel. + execute(this); + } + + public void requestContent(DataFrame frame, Callback callback) + { + // We must copy the data since we do not know when its bytes will be consumed. + ByteBufferPool byteBufferPool = getByteBufferPool(); + ByteBuffer original = frame.getData(); + final ByteBuffer copy = byteBufferPool.acquire(original.remaining(), original.isDirect()); + BufferUtil.clearToFill(copy); + copy.put(original).flip(); + + // TODO: pending refactoring of HttpChannel API (see above). + content(new ByteBufferCallback(byteBufferPool, copy, callback)); + + if (frame.isEndStream()) + { + messageComplete(); + } + } + + @Override + public boolean messageComplete() + { + super.messageComplete(); + return false; } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java index e0ac508d81b..162c006f562 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java @@ -22,27 +22,35 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.server.QueuedHttpInput; -public class HttpInputOverHTTP2 extends QueuedHttpInput +public class HttpInputOverHTTP2 extends QueuedHttpInput { @Override - protected void onContentConsumed(ByteBuffer item) + protected int remaining(ByteBufferCallback item) { + return item.getByteBuffer().remaining(); } @Override - protected int remaining(ByteBuffer item) + protected int get(ByteBufferCallback item, byte[] buffer, int offset, int length) { - return 0; + ByteBuffer byteBuffer = item.getByteBuffer(); + length = Math.min(byteBuffer.remaining(), length); + byteBuffer.get(buffer, offset, length); + return length; } @Override - protected int get(ByteBuffer item, byte[] buffer, int offset, int length) + protected void consume(ByteBufferCallback item, int length) { - return 0; + ByteBuffer byteBuffer = item.getByteBuffer(); + byteBuffer.position(byteBuffer.position() + length); + if (!byteBuffer.hasRemaining()) + onContentConsumed(item); } @Override - protected void consume(ByteBuffer item, int length) + protected void onContentConsumed(ByteBufferCallback item) { + item.succeeded(); } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 685e6d9ee5e..6f882486cbc 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -19,21 +19,80 @@ package org.eclipse.jetty.http2.server; import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.http.HttpGenerator; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http2.IStream; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.server.HttpTransport; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; public class HttpTransportOverHTTP2 implements HttpTransport { + private final AtomicBoolean commit = new AtomicBoolean(); + private final IStream stream = null; + private final HeadersFrame request = null; + @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { + MetaData.Request metaData = (MetaData.Request)request.getMetaData(); + boolean isHeadRequest = HttpMethod.HEAD.is(metaData.getMethod()); + boolean hasContent = BufferUtil.hasContent(content) && !isHeadRequest; + + // TODO: the idea here is this: + // CallbackLease lease = new CallbackLease(callback); + // commit(lease, ...) + // stream.header(lease, frame) + // session.frame(lease, frame) + // generator.generate(lease, frame) + // generateHeader(lease, frame); + // bodyGenerator[frame.getType()].generateBody(lease, frame); + // stream.content(lease, frame) + // ... + // flush(lease) + // + // Problem is that in this way I need to aggregate multiple callbacks for the same lease. + // So it'd need another abstraction that is a Lease+Callback + + if (commit.compareAndSet(false, true)) + { + commit(info, !hasContent, !hasContent ? callback : new Callback.Adapter() + { + @Override + public void failed(Throwable x) + { + // TODO + } + }); + } + else + { + // TODO + } + + if (hasContent) + { + send(content, lastContent, callback); + } + } + + private void commit(HttpGenerator.ResponseInfo info, boolean endStream, Callback callback) + { + MetaData metaData = new MetaData.Response(info.getStatus(), info.getHttpFields()); + HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, endStream); + stream.headers(frame, callback); } @Override public void send(ByteBuffer content, boolean lastContent, Callback callback) { + DataFrame frame = new DataFrame(stream.getId(), content, lastContent); + stream.data(frame, callback); } @Override diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java new file mode 100644 index 00000000000..3efe184263e --- /dev/null +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -0,0 +1,128 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.util.concurrent.atomic.AtomicReference; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.Callback; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +public class HTTP2ServerTest +{ + private Server server; + private ServerConnector connector; + private String path; + private ByteBufferPool byteBufferPool; + private Generator generator; + + private void startServer(HttpServlet servlet) throws Exception + { + server = new Server(); + connector = new ServerConnector(server, new HTTP2ServerConnectionFactory(new HttpConfiguration())); + server.addConnector(connector); + + ServletContextHandler context = new ServletContextHandler(server, "/"); + path = "/test"; + context.addServlet(new ServletHolder(servlet), path); + + byteBufferPool = new MappedByteBufferPool(); + generator = new Generator(byteBufferPool); + + server.start(); + } + + @After + public void dispose() throws Exception + { + server.stop(); + } + + @Test + public void testRequestResponseNoContent() throws Exception + { + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + } + }); + + String host = "localhost"; + int port = connector.getLocalPort(); + HttpFields fields = new HttpFields(); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), + host + ":" + port, host, port, path, fields); + HeadersFrame request = new HeadersFrame(1, metaData, null, true); + Generator.LeaseCallback lease = generator.generate(request, Callback.Adapter.INSTANCE); + + try (SocketChannel client = SocketChannel.open(new InetSocketAddress(host, port))) + { + for (ByteBuffer buffer : lease.getByteBuffers()) + { + client.write(buffer); + } + + ByteBuffer buffer = ByteBuffer.allocate(2048); + client.read(buffer); + buffer.flip(); + + final AtomicReference frameRef = new AtomicReference<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onHeaders(HeadersFrame frame) + { + frameRef.set(frame); + return false; + } + }); + + parser.parse(buffer); + + HeadersFrame response = frameRef.get(); + Assert.assertNotNull(response); + } + + } +} From ab5461d73e77a7edcb450bbceeb911f9a6474bed Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 12:55:21 +0200 Subject: [PATCH 039/269] fixed hpack literal encoding bug --- .../jetty/http2/hpack/HpackContext.java | 8 ++- .../jetty/http2/hpack/HpackEncoder.java | 32 +++++++-- .../eclipse/jetty/http2/hpack/MetaData.java | 69 +++++++++++++++++++ .../jetty/http2/hpack/HpackContextTest.java | 15 ++++ .../jetty/http2/hpack/HpackEncoderTest.java | 1 - .../eclipse/jetty/http2/hpack/HpackTest.java | 55 ++++++++++++++- 6 files changed, 171 insertions(+), 9 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 327033a4d30..69f10a7e1ce 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -30,6 +30,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.util.ArrayQueue; +import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; @@ -104,7 +105,7 @@ public class HpackContext }; private static final Map __staticFieldMap = new HashMap<>(); - private static final Trie __staticNameMap = new ArrayTrie<>(24); + private static final Trie __staticNameMap = new ArrayTernaryTrie<>(true,512); private static final Entry[] __staticTable=new Entry[STATIC_TABLE.length]; static @@ -140,15 +141,18 @@ public class HpackContext default: entry=new StaticEntry(i,new HttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1])); } - + __staticTable[i]=entry; if (entry._field.getValue()!=null) __staticFieldMap.put(entry._field,entry); + if (!added.contains(entry._field.getName())) { added.add(entry._field.getName()); __staticNameMap.put(entry._field.getName(),entry); + if (__staticNameMap.get(entry._field.getName())==null) + throw new IllegalStateException("name trie too small"); } } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 6996d234ee5..7e513e8f076 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -27,6 +27,8 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.io.ByteBufferPool.Lease; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.TypeUtil; public class HpackEncoder { @@ -130,6 +132,13 @@ public class HpackEncoder private void encode(ByteBuffer buffer, HttpField field) { + + /* + System.err.println("encode "+field); + int p=buffer.position(); + try{ + */ + // TODO currently we do not check if there is enough space, so we will always // return true or fail nastily. @@ -142,6 +151,7 @@ public class HpackEncoder if (entry.isInReferenceSet()) { entry.used(); + // System.err.println("In Reference Set"); return; } @@ -163,8 +173,11 @@ public class HpackEncoder // Add the value buffer.put(entry.getStaticHuffmanValue()); + // System.err.println("Literal without Indexing, indexed name"); return; } + + // System.err.println("Indexed from Header Set"); // So we can add the entry to the reference Set and emit the index; _context.addToRefSet(entry); @@ -200,7 +213,7 @@ public class HpackEncoder { reference=true; never_index=false; - huffman=__DO_NOT_HUFFMAN.contains(header); + huffman=!__DO_NOT_HUFFMAN.contains(header); name_bits = 6; mask=(byte)0x40; } @@ -208,17 +221,19 @@ public class HpackEncoder { reference=false; never_index=__NEVER_INDEX.contains(header); - huffman=__DO_NOT_HUFFMAN.contains(header); + huffman=!__DO_NOT_HUFFMAN.contains(header); name_bits = 4; mask=never_index?(byte)0x01:(byte)0x00; } - // Add the mask bits buffer.put(mask); // Look for a name Index Entry name_entry = _context.get(field.getName()); + + // System.err.printf("Literal huff=%b refed=%b neverIdx=%b nameIdx=%b b=%d m=0x%02x%n",huffman,reference,never_index,name_entry!=null,name_bits,mask); + if (name_entry!=null) NBitInteger.encode(buffer,name_bits,_context.index(name_entry)); else @@ -241,7 +256,7 @@ public class HpackEncoder else { // add literal assuming iso_8859_1 - buffer.put((byte)0x80); + buffer.put((byte)0x00); NBitInteger.encode(buffer,7,value.length()); for (int i=0;i return list; } + @Override + public boolean equals(Object o) + { + if (!(o instanceof MetaData)) + return false; + MetaData m = (MetaData)o; + + List lm=m.getFields(); + int s=0; + for (HttpField field: this) + { + s++; + if (!lm.contains(field)) + return false; + } + + if (s!=lm.size()) + return false; + + return true; + } + + @Override + public String toString() + { + StringBuilder out = new StringBuilder(); + for (HttpField field: this) + out.append(field).append('\n'); + return out.toString(); + } + /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ @@ -132,6 +164,27 @@ public class MetaData implements Iterable { return _path; } + + @Override + public boolean equals(Object o) + { + if (!(o instanceof Request)) + return false; + Request r = (Request)o; + if (!_method.equals(r._method) || + !_scheme.equals(r._scheme) || + !_authority.equals(r._authority) || + !_path.equals(r._path)) + return false; + return super.equals(o); + } + + @Override + public String toString() + { + return _method+" "+_scheme+"://"+_authority+_path+" HTTP/2\n"+super.toString(); + } + } /* -------------------------------------------------------- */ @@ -169,5 +222,21 @@ public class MetaData implements Iterable { return _status; } + + @Override + public boolean equals(Object o) + { + if (!(o instanceof Response)) + return false; + Response r = (Response)o; + if (_status!=r._status) + return false; + return super.equals(o); + } + @Override + public String toString() + { + return "HTTP/2 "+_status+"\n"+super.toString(); + } } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java index 138980ded20..8c9a978a2ad 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java @@ -686,4 +686,19 @@ public class HpackContextTest } } + + + + @Test + public void testNameInsensitivity() + { + HpackContext ctx = new HpackContext(4096); + assertEquals("content-length",ctx.get("content-length").getHttpField().getName()); + assertEquals("content-length",ctx.get("Content-Length").getHttpField().getName()); + + ctx.add(new HttpField("Wibble","Wobble")); + assertEquals("Wibble",ctx.get("wibble").getHttpField().getName()); + assertEquals("Wibble",ctx.get("Wibble").getHttpField().getName()); + + } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index 082f588901d..7dee4b407d3 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -267,7 +267,6 @@ public class HpackEncoderTest } - diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index da75ce2a1ff..ab5937e87d9 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -19,16 +19,67 @@ package org.eclipse.jetty.http2.hpack; +import java.nio.ByteBuffer; + import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; +import org.junit.Assert; import org.junit.Test; +import org.eclipse.jetty.http2.hpack.MetaData.Response; +import org.eclipse.jetty.http2.hpack.MetaData.Request; +import org.eclipse.jetty.util.BufferUtil; public class HpackTest { @Test - public void encodeDecodeTest() + public void encodeDecodeResponseTest() { - HttpFields fields = new HttpFields(); + HpackEncoder encoder = new HpackEncoder(); + HpackDecoder decoder = new HpackDecoder(); + ByteBuffer buffer = BufferUtil.allocate(16*1024); + + HttpFields fields0 = new HttpFields(); + fields0.add(HttpHeader.CONTENT_TYPE,"text/html"); + fields0.add(HttpHeader.CONTENT_LENGTH,"1024"); + fields0.add(HttpHeader.SERVER,"jetty"); + fields0.add(HttpHeader.SET_COOKIE,"abcdefghijklmnopqrstuvwxyz"); + fields0.add("custom-key","custom-value"); + Response original0 = new Response(200,fields0); + + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,original0); + BufferUtil.flipToFlush(buffer,0); + Response decoded0 = (Response)decoder.decode(buffer); + + System.err.println(decoded0); + Assert.assertEquals(original0,decoded0); + + // Same again? + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,original0); + BufferUtil.flipToFlush(buffer,0); + Response decoded0b = (Response)decoder.decode(buffer); + + System.err.println(decoded0b); + Assert.assertEquals(original0,decoded0b); + + + HttpFields fields1 = new HttpFields(); + fields1.add(HttpHeader.CONTENT_TYPE,"text/plain"); + fields1.add(HttpHeader.CONTENT_LENGTH,"1234"); + fields1.add(HttpHeader.SERVER,"jetty"); + fields1.add("custom-key","other-value"); + Response original1 = new Response(200,fields1); + + // Same again? + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,original1); + BufferUtil.flipToFlush(buffer,0); + Response decoded1 = (Response)decoder.decode(buffer); + + System.err.println(decoded1); + Assert.assertEquals(original1,decoded1); } From 19c4939ede25e3fcbafe7e69490bc24bfea744af Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 13:05:28 +0200 Subject: [PATCH 040/269] flip encode buffer --- .../eclipse/jetty/http2/hpack/HpackEncoder.java | 14 ++++++++++++++ .../org/eclipse/jetty/http2/hpack/HpackTest.java | 3 --- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 7e513e8f076..94fff2c348a 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -93,9 +93,23 @@ public class HpackEncoder ByteBuffer buffer = lease.acquire(8*1024,false); // TODO make size configurable // TODO handle multiple buffers if large size configured. + BufferUtil.clearToFill(buffer); encode(buffer,metadata); + BufferUtil.flipToFlush(buffer,0); } + public void encodeMaxHeaderTableSize(ByteBuffer buffer, int maxHeaderTableSize) + { + // TODO + _context.resize(maxHeaderTableSize); + } + + public void encodeClearReferenceSet(ByteBuffer buffer) + { + // TODO + _context.clearReferenceSet(); + } + public void encode(ByteBuffer buffer, MetaData metadata) { // Add Request/response meta fields diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index ab5937e87d9..b6c039848c9 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -52,7 +52,6 @@ public class HpackTest BufferUtil.flipToFlush(buffer,0); Response decoded0 = (Response)decoder.decode(buffer); - System.err.println(decoded0); Assert.assertEquals(original0,decoded0); // Same again? @@ -61,7 +60,6 @@ public class HpackTest BufferUtil.flipToFlush(buffer,0); Response decoded0b = (Response)decoder.decode(buffer); - System.err.println(decoded0b); Assert.assertEquals(original0,decoded0b); @@ -78,7 +76,6 @@ public class HpackTest BufferUtil.flipToFlush(buffer,0); Response decoded1 = (Response)decoder.decode(buffer); - System.err.println(decoded1); Assert.assertEquals(original1,decoded1); From b55dba82a59476368d0bd02a58fe7b6ae3fadf5e Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 13:13:38 +0200 Subject: [PATCH 041/269] use scheme cache --- .../java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index ac8361db408..d34ca74f474 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -78,7 +78,7 @@ public class MetaDataBuilder break; case ":scheme": - _scheme = HttpScheme.valueOf(field.getValue()); + _scheme = HttpScheme.CACHE.get(field.getValue()); break; case ":authority": From f2e8edca9c00092629fa19901254df9bea93c2de Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 13:29:50 +0200 Subject: [PATCH 042/269] First working test for end-to-end request/response processing on server side. --- .../http2/server/HTTP2ServerConnectionFactory.java | 3 ++- .../jetty/http2/server/HttpTransportOverHTTP2.java | 10 ++++++++-- .../eclipse/jetty/http2/server/HTTP2ServerTest.java | 9 ++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 145584b353e..dca82371c1a 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.server; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; @@ -82,7 +83,7 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory { LOG.debug("Received {} on {}", frame, stream); - HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2(); + HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2((IStream)stream, frame); HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input); stream.setAttribute(CHANNEL_ATTRIBUTE, channel); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 6f882486cbc..1af79a57305 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -34,8 +34,14 @@ import org.eclipse.jetty.util.Callback; public class HttpTransportOverHTTP2 implements HttpTransport { private final AtomicBoolean commit = new AtomicBoolean(); - private final IStream stream = null; - private final HeadersFrame request = null; + private final IStream stream; + private final HeadersFrame request; + + public HttpTransportOverHTTP2(IStream stream, HeadersFrame request) + { + this.stream = stream; + this.request = request; + } @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 3efe184263e..254bcf70bc8 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -22,6 +22,8 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -80,11 +82,13 @@ public class HTTP2ServerTest @Test public void testRequestResponseNoContent() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); startServer(new HttpServlet() { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + latch.countDown(); } }); @@ -120,9 +124,12 @@ public class HTTP2ServerTest parser.parse(buffer); + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + HeadersFrame response = frameRef.get(); Assert.assertNotNull(response); + MetaData.Response responseMetaData = (MetaData.Response)response.getMetaData(); + Assert.assertEquals(200, responseMetaData.getStatus()); } - } } From 073ad924b052b8e8ea9b23fe38ecbbf3b7ada0ef Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 14:05:14 +0200 Subject: [PATCH 043/269] improve value handling on known literal fields --- .../jetty/http2/hpack/HpackContext.java | 19 -------- .../jetty/http2/hpack/HpackDecoder.java | 38 +++++++++++++-- .../jetty/http2/hpack/MetaDataBuilder.java | 4 +- .../http2/hpack/StaticValueHttpField.java | 46 +++++++++++++++++++ 4 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 69f10a7e1ce..a2fd0ad47c7 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -554,23 +554,4 @@ public class HpackContext } } - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - public static class StaticValueHttpField extends HttpField - { - private final Object _value; - - public StaticValueHttpField(String name, String valueString, Object value) - { - super(name,valueString); - _value=value; - } - - public Object getStaticValue() - { - return _value; - } - } - } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 06e22ac83bc..56a09c5e504 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -23,6 +23,8 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; @@ -119,11 +121,37 @@ public class HpackDecoder // Make the new field HttpField field; - if (":authority".equals(header)) - field = new AuthorityHttpField(value); - else - // Normal Field - field = new HttpField(header,name,value); + switch(name) + { + case ":method": + HttpMethod method=HttpMethod.CACHE.get(value); + if (method!=null) + field = new StaticValueHttpField(header,name,method.asString(),method); + else + field = new AuthorityHttpField(value); + break; + + case ":status": + Integer code = Integer.getInteger(value); + field = new StaticValueHttpField(header,name,value,code); + break; + + case ":scheme": + HttpScheme scheme=HttpScheme.CACHE.get(value); + if (scheme!=null) + field = new StaticValueHttpField(header,name,scheme.asString(),scheme); + else + field = new AuthorityHttpField(value); + break; + + case ":authority": + field = new AuthorityHttpField(value); + break; + + default: + field = new HttpField(header,name,value); + break; + } // emit the field _builder.emit(field); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index d34ca74f474..6657c7899eb 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -43,9 +43,9 @@ public class MetaDataBuilder public void emit(HttpField field) { - if (field instanceof HpackContext.StaticValueHttpField) + if (field instanceof StaticValueHttpField) { - HpackContext.StaticValueHttpField value = (HpackContext.StaticValueHttpField)field; + StaticValueHttpField value = (StaticValueHttpField)field; switch(field.getName()) { case ":status": diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java new file mode 100644 index 00000000000..4a3d73e42d5 --- /dev/null +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java @@ -0,0 +1,46 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http2.hpack; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpHeader; + +/* ------------------------------------------------------------ */ +public class StaticValueHttpField extends HttpField +{ + private final Object _value; + + public StaticValueHttpField(HttpHeader header,String name, String valueString, Object value) + { + super(header,name,valueString); + _value=value; + } + + public StaticValueHttpField(String name, String valueString, Object value) + { + super(name,valueString); + _value=value; + } + + public Object getStaticValue() + { + return _value; + } +} \ No newline at end of file From c8184077c7be56d1ffebebf468f70c353a0b4efb Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 15:26:54 +0200 Subject: [PATCH 044/269] added logging to hpack --- .../jetty/http2/hpack/HpackContext.java | 19 +- .../jetty/http2/hpack/HpackDecoder.java | 33 ++- .../jetty/http2/hpack/HpackEncoder.java | 248 +++++++++--------- .../http2/hpack/StaticValueHttpField.java | 4 + .../jetty/http2/server/HTTP2ServerTest.java | 7 + 5 files changed, 178 insertions(+), 133 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index a2fd0ad47c7..58c4e13af67 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -31,12 +31,15 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.ArrayTernaryTrie; -import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class HpackContext { + public static final Logger LOG = Log.getLogger(HpackContext.class); + public static final String[][] STATIC_TABLE = { {null,null}, @@ -182,6 +185,7 @@ public class HpackContext public void resize(int maxHeaderTableSize) { + LOG.debug("HdrTbl resized {}",maxHeaderTableSize); _maxHeaderTableSizeInBytes=maxHeaderTableSize; int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10); evict(); @@ -223,12 +227,16 @@ public class HpackContext Entry entry=new Entry(i,field); int size = entry.getSize(); if (size>_maxHeaderTableSizeInBytes) + { + LOG.debug("!added {} too big",field); return null; + } _headerTableSizeInBytes+=size; _headerTable.addUnsafe(entry); _fieldMap.put(field,entry); _nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry); + LOG.debug("HdrTbl added {}",entry); evict(); return entry; } @@ -249,6 +257,7 @@ public class HpackContext public void addToRefSet(Entry entry) { + LOG.debug("RefSet added {}",entry); entry.addToRefSet(this); } @@ -259,6 +268,7 @@ public class HpackContext public void clearReferenceSet() { + LOG.debug("RefSet cleared"); Entry entry = _refSet._refSetNext; while(entry!=_refSet) { @@ -280,6 +290,7 @@ public class HpackContext entry._used=false; else { + LOG.debug("RefSet remove unused {}",entry); // encode the reference to remove it buffer.put((byte)0x80); NBitInteger.encode(buffer,7,index(entry)); @@ -297,7 +308,10 @@ public class HpackContext if (entry.isUsed()) entry._used=false; else + { + LOG.debug("RefSet emit unused {}",entry); builder.emit(entry.getHttpField()); + } entry=entry._refSetNext; } @@ -342,6 +356,7 @@ public class HpackContext while (_headerTableSizeInBytes>_maxHeaderTableSizeInBytes) { Entry entry = _headerTable.pollUnsafe(); + LOG.debug("HdrTbl evict {}",entry); _headerTableSizeInBytes-=entry.getSize(); entry.removeFromRefSet(); entry._index=-1; @@ -460,6 +475,7 @@ public class HpackContext _refSetPrev=ctx._refSet._refSetPrev; ctx._refSet._refSetPrev._refSetNext=this; ctx._refSet._refSetPrev=this; + LOG.debug("RefSet add {}",this); } public boolean isInReferenceSet() @@ -469,6 +485,7 @@ public class HpackContext public void removeFromRefSet() { + LOG.debug("RefSet remove {}",this); if (_refSetNext!=this) { _refSetNext._refSetPrev=_refSetPrev; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 56a09c5e504..2ecb070ff09 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -26,6 +26,9 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; +import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ @@ -34,6 +37,8 @@ import org.eclipse.jetty.http2.hpack.HpackContext.Entry; */ public class HpackDecoder { + public static final Logger LOG = Log.getLogger(HpackDecoder.class); + private final HpackContext _context; private final MetaDataBuilder _builder = new MetaDataBuilder(); @@ -48,10 +53,15 @@ public class HpackDecoder } public MetaData decode(ByteBuffer buffer) - { - + { while(buffer.hasRemaining()) { + if (LOG.isDebugEnabled()) + { + int l=Math.min(buffer.remaining(),16); + LOG.debug("decode "+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l)+(l=4; int bits=indexed?6:4; + boolean huffmanName=false; // decode the name int name_index=NBitInteger.decode(buffer,bits); @@ -102,9 +115,9 @@ public class HpackDecoder } else { - boolean huffman = (buffer.get()&0x80)==0x80; + huffmanName = (buffer.get()&0x80)==0x80; int length = NBitInteger.decode(buffer,7); - if (huffman) + if (huffmanName) name=Huffman.decode(buffer,length); else name=toASCIIString(buffer,length); @@ -112,9 +125,9 @@ public class HpackDecoder } // decode the value - boolean huffman = (buffer.get()&0x80)==0x80; + boolean huffmanValue = (buffer.get()&0x80)==0x80; int length = NBitInteger.decode(buffer,7); - if (huffman) + if (huffmanValue) value=Huffman.decode(buffer,length); else value=toASCIIString(buffer,length); @@ -132,7 +145,7 @@ public class HpackDecoder break; case ":status": - Integer code = Integer.getInteger(value); + Integer code = Integer.valueOf(value); field = new StaticValueHttpField(header,name,value,code); break; @@ -153,6 +166,9 @@ public class HpackDecoder break; } + if (LOG.isDebugEnabled()) + LOG.debug("decoded '"+field+"' by Lit"+(name_index>0?"IdxName":(huffmanName?"HuffName":"LitName"))+(huffmanValue?"HuffVal":"LitVal")+(indexed?"Idx":"")); + // emit the field _builder.emit(field); @@ -170,11 +186,14 @@ public class HpackDecoder { // change table size int size = NBitInteger.decode(buffer,4); + if (LOG.isDebugEnabled()) + LOG.debug("decode resize="+size); _context.resize(size); } else if (f==3) { // clear reference set + LOG.debug("decode clear"); _context.clearReferenceSet(); } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 94fff2c348a..b9d947d1242 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -29,9 +29,13 @@ import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.io.ByteBufferPool.Lease; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class HpackEncoder { + public static final Logger LOG = Log.getLogger(HpackEncoder.class); + private final static HttpField[] __status= new HttpField[599]; private final static EnumSet __NEVER_INDEX = @@ -100,7 +104,6 @@ public class HpackEncoder public void encodeMaxHeaderTableSize(ByteBuffer buffer, int maxHeaderTableSize) { - // TODO _context.resize(maxHeaderTableSize); } @@ -143,34 +146,29 @@ public class HpackEncoder _context.removedUnusedReferences(buffer); } - + private void encode(ByteBuffer buffer, HttpField field) { - - /* - System.err.println("encode "+field); - int p=buffer.position(); - try{ - */ - + final int p=LOG.isDebugEnabled()?buffer.position():-1; + String encoding=null; + // TODO currently we do not check if there is enough space, so we will always // return true or fail nastily. - + // Is there an entry for the field? Entry entry = _context.get(field); - + if (entry!=null) { // if entry is already in the reference set, then nothing more to do. if (entry.isInReferenceSet()) { entry.used(); - // System.err.println("In Reference Set"); - return; + encoding="InRefSet"; } - + // Is this as static field - if (entry.isStatic()) + else if (entry.isStatic()) { // TODO Strategy decision to make! // Should we add to reference set or just always send as indexed? @@ -179,130 +177,130 @@ public class HpackEncoder // lets send as literal header, indexed name. // We don't need never indexed because the cookie fields are name only and we can // huffman encode the value for the same reason. - + // Add the token buffer.put((byte)0x00); // Add the name index NBitInteger.encode(buffer,4,_context.index(entry)); // Add the value buffer.put(entry.getStaticHuffmanValue()); - - // System.err.println("Literal without Indexing, indexed name"); - return; + + encoding="LiteralStaticIdxNameHuffmanValue"; } - - // System.err.println("Indexed from Header Set"); - - // So we can add the entry to the reference Set and emit the index; - _context.addToRefSet(entry); - int index=_context.index(entry); - - // TODO pregenerate indexes? - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,index); - return; - } - - - // Must be a new entry, so we will have to send literally. - // TODO Strategy decision to make! - // What fields will we put in the reference set and what fields will we huffman encode? - - // Let's make these decisions by lookup of known fields - HttpHeader header = field.getHeader(); - final boolean never_index; - final boolean huffman; - final boolean reference; - final int name_bits; - final byte mask; - if (header==null) - { - never_index=false; - huffman=true; - reference=true; - name_bits = 6; - mask=(byte)0x40; - } - else if (__USE_REFERENCE_SET.contains(header)) - { - reference=true; - never_index=false; - huffman=!__DO_NOT_HUFFMAN.contains(header); - name_bits = 6; - mask=(byte)0x40; - } - else - { - reference=false; - never_index=__NEVER_INDEX.contains(header); - huffman=!__DO_NOT_HUFFMAN.contains(header); - name_bits = 4; - mask=never_index?(byte)0x01:(byte)0x00; - } - - // Add the mask bits - buffer.put(mask); - - // Look for a name Index - Entry name_entry = _context.get(field.getName()); - - // System.err.printf("Literal huff=%b refed=%b neverIdx=%b nameIdx=%b b=%d m=0x%02x%n",huffman,reference,never_index,name_entry!=null,name_bits,mask); - - if (name_entry!=null) - NBitInteger.encode(buffer,name_bits,_context.index(name_entry)); - else - { - // Encode the name always with huffman - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeeded(field.getName())); - Huffman.encode(buffer,field.getName()); - } - - // Add the literal value - String value=field.getValue(); - if (huffman) - { - // huffman literal value - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeeded(value)); - Huffman.encode(buffer,field.getValue()); - } - else - { - // add literal assuming iso_8859_1 - buffer.put((byte)0x00); - NBitInteger.encode(buffer,7,value.length()); - for (int i=0;i127) - throw new IllegalArgumentException(); - buffer.put((byte)c); + encoding="IdxField"; + + // So we can add the entry to the reference Set and emit the index; + _context.addToRefSet(entry); + int index=_context.index(entry); + + // TODO pregenerate indexes? + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,index); } } - - // If we want the field referenced, then we add it to our - // table and reference set. - if (reference) + else { - Entry new_entry=_context.add(field); - if (new_entry!=null) - _context.addToRefSet(new_entry); + // Must be a new entry, so we will have to send literally. + // TODO Strategy decision to make! + // What fields will we put in the reference set and what fields will we huffman encode? + + // Let's make these decisions by lookup of known fields + HttpHeader header = field.getHeader(); + final boolean never_index; + final boolean huffman; + final boolean reference; + final int name_bits; + final byte mask; + if (header==null) + { + never_index=false; + huffman=true; + reference=true; + name_bits = 6; + mask=(byte)0x40; + } + else if (__USE_REFERENCE_SET.contains(header)) + { + reference=true; + never_index=false; + huffman=!__DO_NOT_HUFFMAN.contains(header); + name_bits = 6; + mask=(byte)0x40; + } + else + { + reference=false; + never_index=__NEVER_INDEX.contains(header); + huffman=!__DO_NOT_HUFFMAN.contains(header); + name_bits = 4; + mask=never_index?(byte)0x01:(byte)0x00; + } + + // Add the mask bits + buffer.put(mask); + + // Look for a name Index + Entry name_entry = _context.get(field.getName()); + + if (p>=0) + { + encoding="Literal"+ + ((name_entry==null)?"IdxName":"HuffName")+ + (huffman?"HuffName":"LitName")+ + (reference?"Idx":(never_index?"NeverIdx":"")); + } + + if (name_entry!=null) + NBitInteger.encode(buffer,name_bits,_context.index(name_entry)); + else + { + // Encode the name always with huffman + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,Huffman.octetsNeeded(field.getName())); + Huffman.encode(buffer,field.getName()); + } + + // Add the literal value + String value=field.getValue(); + if (huffman) + { + // huffman literal value + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,Huffman.octetsNeeded(value)); + Huffman.encode(buffer,field.getValue()); + } + else + { + // add literal assuming iso_8859_1 + buffer.put((byte)0x00); + NBitInteger.encode(buffer,7,value.length()); + for (int i=0;i127) + throw new IllegalArgumentException(); + buffer.put((byte)c); + } + } + + // If we want the field referenced, then we add it to our + // table and reference set. + if (reference) + { + Entry new_entry=_context.add(field); + if (new_entry!=null) + _context.addToRefSet(new_entry); + } + + } - - return; - - /* - } - finally + + if (p>=0) { int e=buffer.position(); - System.err.println("'"+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)+"'"); + LOG.debug("encoded '{}' by {} to '{}'",field,encoding,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); } - */ } - - - - } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java index 4a3d73e42d5..b26345626c3 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java @@ -30,12 +30,16 @@ public class StaticValueHttpField extends HttpField public StaticValueHttpField(HttpHeader header,String name, String valueString, Object value) { super(header,name,valueString); + if (value==null) + throw new IllegalArgumentException(); _value=value; } public StaticValueHttpField(String name, String valueString, Object value) { super(name,valueString); + if (value==null) + throw new IllegalArgumentException(); _value=value; } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 254bcf70bc8..8ffd237eebd 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -25,6 +25,7 @@ import java.nio.channels.SocketChannel; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -35,6 +36,9 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.hpack.HpackContext; +import org.eclipse.jetty.http2.hpack.HpackDecoder; +import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; @@ -71,6 +75,9 @@ public class HTTP2ServerTest generator = new Generator(byteBufferPool); server.start(); + HpackContext.LOG.setDebugEnabled(true); + HpackEncoder.LOG.setDebugEnabled(true); + HpackDecoder.LOG.setDebugEnabled(true); } @After From 36e7c41b2fbba281d012110c251d18b558a6f20a Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 16:02:04 +0200 Subject: [PATCH 045/269] Improved logging. --- .../org/eclipse/jetty/http2/HTTP2Stream.java | 6 ++++++ .../org/eclipse/jetty/http2/frames/Frame.java | 6 ++++++ .../eclipse/jetty/http2/frames/FrameType.java | 14 +++++++++++++ .../eclipse/jetty/http2/parser/Parser.java | 6 ++++++ .../server/HTTP2ServerConnectionFactory.java | 6 ++++-- .../http2/server/HttpChannelOverHTTP2.java | 20 ++++++++++++++++++- .../http2/server/HttpTransportOverHTTP2.java | 17 ++++++++++++++++ .../test/resources/jetty-logging.properties | 2 ++ 8 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 jetty-http2/http2-server/src/test/resources/jetty-logging.properties diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 1a5304f1d70..053591b6db2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -125,4 +125,10 @@ public class HTTP2Stream implements IStream }); return true; } + + @Override + public String toString() + { + return String.format("%s@%x", getClass().getSimpleName(), hashCode()); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java index 7a58eb21841..782b6480c98 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java @@ -34,4 +34,10 @@ public abstract class Frame { return type; } + + @Override + public String toString() + { + return String.format("%s@%x", getClass().getSimpleName(), hashCode()); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java index f46855d0eaa..a84898bd2b8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java @@ -18,6 +18,9 @@ package org.eclipse.jetty.http2.frames; +import java.util.HashMap; +import java.util.Map; + public enum FrameType { DATA(0), @@ -33,15 +36,26 @@ public enum FrameType ALTSVC(10), BLOCKED(11); + public static FrameType from(int type) + { + return Types.types.get(type); + } + private final int type; private FrameType(int type) { this.type = type; + Types.types.put(type, this); } public int getType() { return type; } + + private static class Types + { + private static final Map types = new HashMap<>(); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index b1d7f843d39..b6012e41b0f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -71,6 +71,8 @@ public class Parser public boolean parse(ByteBuffer buffer) { + LOG.debug("Parsing {}", buffer); + while (true) { switch (state) @@ -114,10 +116,14 @@ public class Parser { // The content will be processed asynchronously, stop parsing; // the asynchronous operation will eventually resume parsing. + if (LOG.isDebugEnabled()) + LOG.debug("Parsed {} frame, asynchronous processing", FrameType.from(type)); return true; } case COMPLETE: { + if (LOG.isDebugEnabled()) + LOG.debug("Parsed {} frame, synchronous processing", FrameType.from(type)); reset(); break; } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index dca82371c1a..b6ff00853c6 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -81,11 +81,11 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { - LOG.debug("Received {} on {}", frame, stream); + LOG.debug("Processing {} on {}", frame, stream); HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2((IStream)stream, frame); HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); - HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input); + HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input, stream); stream.setAttribute(CHANNEL_ATTRIBUTE, channel); channel.requestHeaders(frame); @@ -96,6 +96,8 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory @Override public void onData(Stream stream, DataFrame frame, Callback callback) { + LOG.debug("Processing {} on {}", frame, stream); + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(CHANNEL_ATTRIBUTE); channel.requestContent(frame, callback); } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index f64005f2697..bd23ace1fd6 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -25,6 +25,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.hpack.MetaData; @@ -37,12 +38,18 @@ import org.eclipse.jetty.server.HttpInput; import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class HttpChannelOverHTTP2 extends HttpChannel { - public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) + private static final Logger LOG = Log.getLogger(HttpChannelOverHTTP2.class); + private final Stream stream; + + public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input, Stream stream) { super(connector, configuration, endPoint, transport, input); + this.stream = stream; } public void requestHeaders(HeadersFrame frame) @@ -84,6 +91,17 @@ public class HttpChannelOverHTTP2 extends HttpChannel messageComplete(); } + if (LOG.isDebugEnabled()) + { + StringBuilder headers = new StringBuilder(); + for (HttpField field : fields) + { + headers.append(field).append(System.lineSeparator()); + } + LOG.debug("HTTP2 Request #{}:{}{} {} {}{}{}", + stream.getId(), System.lineSeparator(), method, uri, version, System.lineSeparator(), headers); + } + // TODO: pending refactoring of HttpChannel API. // Here we "cheat", knowing that headerComplete() will always return true // and that content() and messageComplete() will always return false. diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 1af79a57305..50e52278912 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -30,9 +31,13 @@ import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class HttpTransportOverHTTP2 implements HttpTransport { + private static final Logger LOG = Log.getLogger(HttpTransportOverHTTP2.class); + private final AtomicBoolean commit = new AtomicBoolean(); private final IStream stream; private final HeadersFrame request; @@ -89,6 +94,12 @@ public class HttpTransportOverHTTP2 implements HttpTransport private void commit(HttpGenerator.ResponseInfo info, boolean endStream, Callback callback) { + if (LOG.isDebugEnabled()) + { + LOG.debug("HTTP2 Response #{}:{}{} {}{}{}", + stream.getId(), System.lineSeparator(), HttpVersion.HTTP_2_0, info.getStatus(), System.lineSeparator(), info.getHttpFields()); + } + MetaData metaData = new MetaData.Response(info.getStatus(), info.getHttpFields()); HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, endStream); stream.headers(frame, callback); @@ -97,6 +108,12 @@ public class HttpTransportOverHTTP2 implements HttpTransport @Override public void send(ByteBuffer content, boolean lastContent, Callback callback) { + if (LOG.isDebugEnabled()) + { + LOG.debug("HTTP2 Response #{}: {} {}content bytes", + stream.getId(), lastContent ? "last " : "", content.remaining()); + } + DataFrame frame = new DataFrame(stream.getId(), content, lastContent); stream.data(frame, callback); } diff --git a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..13ddd0bba9d --- /dev/null +++ b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties @@ -0,0 +1,2 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.http2.LEVEL=DEBUG From 24cda181142c44414c912d61777c92378318fb5b Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 16:38:54 +0200 Subject: [PATCH 046/269] http2 test server --- jetty-http2/http2-server/pom.xml | 12 ++ .../server/HTTP2ServerConnectionFactory.java | 2 +- .../jetty/http2/server/Http2Server.java | 125 ++++++++++++++++++ .../test/resources/jetty-logging.properties | 3 + 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java create mode 100644 jetty-http2/http2-server/src/test/resources/jetty-logging.properties diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index 814ad7fd6ca..8a26f2ec76c 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -65,6 +65,18 @@ ${project.version} test + + org.eclipse.jetty.spdy + spdy-server + ${project.version} + test + + + org.eclipse.jetty.npn + npn-api + ${npn.api.version} + test + diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index dca82371c1a..80439b175b9 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -46,7 +46,7 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory public HTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration) { - super("h2"); + super("h2-12"); this.httpConfiguration = httpConfiguration; } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java new file mode 100644 index 00000000000..f6da10c5e06 --- /dev/null +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java @@ -0,0 +1,125 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http2.server; + +import java.io.IOException; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.hpack.HpackContext; +import org.eclipse.jetty.http2.hpack.HpackDecoder; +import org.eclipse.jetty.http2.hpack.HpackEncoder; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.eclipse.jetty.npn.NextProtoNego; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; +import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; + + +/* ------------------------------------------------------------ */ +/** + */ +public class Http2Server +{ + public static void main(String... args) throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(server, "/"); + context.setResourceBase("/tmp"); + context.addServlet(new ServletHolder(servlet), "/test/*"); + context.addServlet(DefaultServlet.class, "/"); + server.setHandler(context); + + + // HTTP Configuration + HttpConfiguration http_config = new HttpConfiguration(); + http_config.setSecureScheme("https"); + http_config.setSecurePort(8443); + + // HTTP connector + ServerConnector http = new ServerConnector(server,new HttpConnectionFactory(http_config)); + http.setPort(8080); + server.addConnector(http); + + // SSL Context Factory for HTTPS and SPDY + String jetty_distro = System.getProperty("jetty.distro","../../jetty-distribution/target/distribution"); + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath(jetty_distro + "/etc/keystore"); + sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); + sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); + + // HTTPS Configuration + HttpConfiguration https_config = new HttpConfiguration(http_config); + https_config.addCustomizer(new SecureRequestCustomizer()); + + + // HTTP2 factory + HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); + + SPDYServerConnectionFactory.checkProtocolNegotiationAvailable(); + NPNServerConnectionFactory npn = + new NPNServerConnectionFactory(h2.getProtocol(),http.getDefaultProtocol()); + npn.setDefaultProtocol(http.getDefaultProtocol()); + + // SSL Factory + SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,npn.getProtocol()); + + // SPDY Connector + ServerConnector http2Connector = + new ServerConnector(server,ssl,npn,h2,new HttpConnectionFactory(https_config)); + http2Connector.setPort(8443); + server.addConnector(http2Connector); + + NextProtoNego.debug=true; + + server.start(); + server.dumpStdErr(); + server.join(); + } + + + static Servlet servlet = new HttpServlet() + { + private static final long serialVersionUID = 1L; + + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + response.setHeader("custom","value"); + response.setContentType("text/plain"); + response.getOutputStream().print("Hello from Jetty HTTP2"); + } + }; +} diff --git a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..9e22652e722 --- /dev/null +++ b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.client.LEVEL=DEBUG +org.eclipse.jetty.spdy.server.LEVEL=DEBUG From 7aeddff6754ea81794a177a0f91d1c11bd4c0dfa Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 18:08:44 +0200 Subject: [PATCH 047/269] Changed method acquire() to not append(), to allow callers to decide whether to append() or prepend the returned buffer. --- jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index b9e9e0978b0..cce31a0cd52 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -70,7 +70,6 @@ public interface ByteBufferPool { ByteBuffer buffer = byteBufferPool.acquire(capacity, direct); BufferUtil.clearToFill(buffer); - append(buffer, true); return buffer; } From 630bee58872e40feffd5584542811421a43f795c Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 18:08:57 +0200 Subject: [PATCH 048/269] Implemented HTTP2 connection preface. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 5 + .../eclipse/jetty/http2/parser/Parser.java | 6 +- .../jetty/http2/parser/PrefaceParser.java | 75 ++++++++++++ .../jetty/http2/parser/ServerParser.java | 109 ++++++++++++++++++ .../jetty/http2/hpack/HpackEncoder.java | 2 +- .../server/HTTP2ServerConnectionFactory.java | 6 +- .../http2/server/HTTP2ServerSession.java | 22 +++- .../jetty/http2/server/HTTP2ServerTest.java | 49 ++++++-- 8 files changed, 256 insertions(+), 18 deletions(-) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index b0f5a8ec116..6ffa9e8df41 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -149,6 +149,11 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.flush(lease); } + protected void disconnect() + { + endPoint.close(); + } + protected IStream putIfAbsent(IStream stream) { return streams.putIfAbsent(stream.getId(), stream); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index b6012e41b0f..a633f61bbba 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -38,14 +38,16 @@ public class Parser { private static final Logger LOG = Log.getLogger(Parser.class); - private final HeaderParser headerParser = new HeaderParser(); - private final BodyParser[] bodyParsers = new BodyParser[FrameType.values().length]; private final Listener listener; + private final HeaderParser headerParser; + private final BodyParser[] bodyParsers; private State state = State.HEADER; public Parser(ByteBufferPool byteBufferPool, Listener listener) { this.listener = listener; + this.headerParser = new HeaderParser(); + this.bodyParsers = new BodyParser[FrameType.values().length]; HeaderBlockParser headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java new file mode 100644 index 00000000000..9c029e34517 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java @@ -0,0 +1,75 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class PrefaceParser +{ + private static final Logger LOG = Log.getLogger(PrefaceParser.class); + public static final byte[] PREFACE_BYTES = new byte[] + { + 0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54, + 0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a, + 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a + }; + private final Parser.Listener listener; + + private int cursor; + + public PrefaceParser(Parser.Listener listener) + { + this.listener = listener; + } + + public boolean parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + int currByte = buffer.get(); + if (currByte != PREFACE_BYTES[cursor]) + { + notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_preface"); + return false; + } + ++cursor; + if (cursor == PREFACE_BYTES.length) + { + cursor = 0; + return true; + } + } + return false; + } + + protected void notifyConnectionFailure(int error, String reason) + { + try + { + listener.onConnectionFailure(error, reason); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java new file mode 100644 index 00000000000..f20328b30c4 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java @@ -0,0 +1,109 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class ServerParser extends Parser +{ + private static final Logger LOG = Log.getLogger(ServerParser.class); + + private final Listener listener; + private final PrefaceParser prefaceParser; + private State state = State.PREFACE; + + public ServerParser(ByteBufferPool byteBufferPool, Listener listener) + { + super(byteBufferPool, listener); + this.listener = listener; + this.prefaceParser = new PrefaceParser(listener); + } + + @Override + public boolean parse(ByteBuffer buffer) + { + LOG.debug("Parsing {}", buffer); + + while (true) + { + switch (state) + { + case PREFACE: + { + if (!prefaceParser.parse(buffer)) + return false; + if (onPreface()) + return true; + state = State.FRAMES; + break; + } + case FRAMES: + { + // Stay forever in the FRAMES state. + return super.parse(buffer); + } + default: + { + throw new IllegalStateException(); + } + } + } + } + + protected boolean onPreface() + { + return notifyPreface(); + } + + private boolean notifyPreface() + { + try + { + return listener.onPreface(); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + + public interface Listener extends Parser.Listener + { + public boolean onPreface(); + + public static class Adapter extends Parser.Listener.Adapter implements Listener + { + @Override + public boolean onPreface() + { + return false; + } + } + } + + private enum State + { + PREFACE, FRAMES + } +} diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index b9d947d1242..fd5e6bff90b 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -95,7 +95,7 @@ public class HpackEncoder public void encode(MetaData metadata,Lease lease) { ByteBuffer buffer = lease.acquire(8*1024,false); // TODO make size configurable - + lease.append(buffer,true); // TODO handle multiple buffers if large size configured. BufferUtil.clearToFill(buffer); encode(buffer,metadata); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index fe656685a49..2d2a581dc0f 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.http2.server; import org.eclipse.jetty.http2.HTTP2Connection; -import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; @@ -28,6 +27,7 @@ import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.AbstractConnectionFactory; @@ -56,9 +56,9 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory Session.Listener listener = new HTTPServerSessionListener(connector, httpConfiguration, endPoint); Generator generator = new Generator(connector.getByteBufferPool()); - HTTP2Session session = new HTTP2ServerSession(endPoint, generator, listener); + HTTP2ServerSession session = new HTTP2ServerSession(endPoint, generator, listener); - Parser parser = new Parser(connector.getByteBufferPool(), session); + Parser parser = new ServerParser(connector.getByteBufferPool(), session); HTTP2Connection connection = new HTTP2Connection(connector.getByteBufferPool(), connector.getExecutor(), endPoint, parser, getInputBufferSize()); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index a0a3f3f735d..45939982ea7 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -18,21 +18,41 @@ package org.eclipse.jetty.http2.server; +import java.util.HashMap; + import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.HTTP2Stream; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.Callback; -public class HTTP2ServerSession extends HTTP2Session +public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Listener { public HTTP2ServerSession(EndPoint endPoint, Generator generator, Listener listener) { super(endPoint, generator, listener); } + @Override + public boolean onPreface() + { + frame(new SettingsFrame(new HashMap(), false), new Callback.Adapter() + { + @Override + public void failed(Throwable x) + { + // If cannot write the SETTINGS frame, hard disconnect. + disconnect(); + } + }); + return false; + } + @Override public boolean onHeaders(HeadersFrame frame) { diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 8ffd237eebd..2b7b1c47013 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -18,14 +18,16 @@ package org.eclipse.jetty.http2.server; +import java.io.EOFException; import java.io.IOException; -import java.net.InetSocketAddress; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -35,12 +37,14 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.hpack.HpackContext; import org.eclipse.jetty.http2.hpack.HpackDecoder; import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.server.HttpConfiguration; @@ -48,6 +52,7 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.junit.After; import org.junit.Assert; @@ -89,7 +94,7 @@ public class HTTP2ServerTest @Test public void testRequestResponseNoContent() throws Exception { - final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch latch = new CountDownLatch(3); startServer(new HttpServlet() { @Override @@ -106,30 +111,52 @@ public class HTTP2ServerTest host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); Generator.LeaseCallback lease = generator.generate(request, Callback.Adapter.INSTANCE); + lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); - try (SocketChannel client = SocketChannel.open(new InetSocketAddress(host, port))) + try (Socket client = new Socket(host, port)) { + OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) { - client.write(buffer); + output.write(BufferUtil.toArray(buffer)); } - ByteBuffer buffer = ByteBuffer.allocate(2048); - client.read(buffer); - buffer.flip(); - final AtomicReference frameRef = new AtomicReference<>(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { + @Override + public boolean onSettings(SettingsFrame frame) + { + latch.countDown(); + return false; + } + @Override public boolean onHeaders(HeadersFrame frame) { frameRef.set(frame); + latch.countDown(); return false; } }); - parser.parse(buffer); + byte[] buffer = new byte[2048]; + InputStream input = client.getInputStream(); + client.setSoTimeout(1000); + while (true) + { + try + { + int read = input.read(buffer); + if (read <= 0) + throw new EOFException(); + parser.parse(ByteBuffer.wrap(buffer, 0, read)); + } + catch (SocketTimeoutException x) + { + break; + } + } Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); From d024a4632790609eb4c3d0ed0b25983d20cfdf19 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 19:05:35 +0200 Subject: [PATCH 049/269] debug --- .../main/java/org/eclipse/jetty/http2/parser/Parser.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index a633f61bbba..302c29258db 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -31,6 +31,7 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.hpack.HpackDecoder; import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -73,7 +74,11 @@ public class Parser public boolean parse(ByteBuffer buffer) { - LOG.debug("Parsing {}", buffer); + if (LOG.isDebugEnabled()) + { + int l=Math.min(buffer.remaining(),16); + LOG.debug("Parsing "+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l)+(l Date: Tue, 10 Jun 2014 20:28:52 +0200 Subject: [PATCH 050/269] improved debug --- .../main/java/org/eclipse/jetty/http2/parser/BodyParser.java | 1 + .../src/main/java/org/eclipse/jetty/http2/parser/Parser.java | 2 +- .../java/org/eclipse/jetty/http2/server/Http2Server.java | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 51fcfda05b9..acdb8e870c7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -165,6 +165,7 @@ public abstract class BodyParser { try { + LOG.debug("goaway: error="+frame.getError()); return listener.onGoAway(frame); } catch (Throwable x) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 302c29258db..abdb3156866 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -130,7 +130,7 @@ public class Parser case COMPLETE: { if (LOG.isDebugEnabled()) - LOG.debug("Parsed {} frame, synchronous processing", FrameType.from(type)); + LOG.debug("Parsed {} frame, synchronous processing: {}", FrameType.from(type),bodyParser); reset(); break; } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java index f6da10c5e06..7ce93c389a2 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java @@ -118,8 +118,11 @@ public class Http2Server protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("custom","value"); + response.sendRedirect("http://www.google.com"); response.setContentType("text/plain"); - response.getOutputStream().print("Hello from Jetty HTTP2"); + String content = "Hello from Jetty HTTP2\n"; + response.setContentLength(content.length()); + response.getOutputStream().print(content); } }; } From 13b0b90aa9b421bc2b54e3826ce014536a24b2d1 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 22:19:55 +0200 Subject: [PATCH 051/269] Fixed logging. --- .../eclipse/jetty/http2/server/HttpTransportOverHTTP2.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 50e52278912..cf9c94cfe9b 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -110,8 +110,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (LOG.isDebugEnabled()) { - LOG.debug("HTTP2 Response #{}: {} {}content bytes", - stream.getId(), lastContent ? "last " : "", content.remaining()); + LOG.debug("HTTP2 Response #{}: {} content bytes{}", + stream.getId(), content.remaining(), lastContent ? " (last chunk)" : ""); } DataFrame frame = new DataFrame(stream.getId(), content, lastContent); From 3c6663ff218c63eafd07d1b6390c053f4d0c3c82 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 10 Jun 2014 22:54:07 +0200 Subject: [PATCH 052/269] Fixed parsing in case of zero-length header block and zero-length data. --- .../jetty/http2/parser/DataBodyParser.java | 18 +-- .../jetty/http2/parser/HeadersBodyParser.java | 25 ++-- .../jetty/http2/server/HTTP2ServerTest.java | 116 +++++++++++++++--- 3 files changed, 121 insertions(+), 38 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index 41c2f9a6328..84cff736310 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -55,7 +55,8 @@ public class DataBodyParser extends BodyParser @Override public Result parse(ByteBuffer buffer) { - while (buffer.hasRemaining()) + boolean loop = false; + while (buffer.hasRemaining() || loop) { switch (state) { @@ -79,7 +80,7 @@ public class DataBodyParser extends BodyParser case PADDING_HIGH: { paddingLength = (buffer.get() & 0xFF) << 8; - length -= 1; + --length; if (length < 1 + 256) { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame_padding"); @@ -90,13 +91,14 @@ public class DataBodyParser extends BodyParser case PADDING_LOW: { paddingLength += buffer.get() & 0xFF; - length -= 1; - if (length < paddingLength) + --length; + length -= paddingLength; + state = State.DATA; + loop = length == 0; + if (length < 0) { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame_padding"); } - length -= paddingLength; - state = State.DATA; break; } case DATA: @@ -110,6 +112,7 @@ public class DataBodyParser extends BodyParser buffer.position(position + size); length -= size; + loop = paddingLength == 0; if (length == 0) { state = State.PADDING; @@ -120,7 +123,8 @@ public class DataBodyParser extends BodyParser } else { - // We got partial data, fake the frame. + // TODO: check the semantic of Flag.END_SEGMENT. + // We got partial data, simulate a smaller frame, and stay in DATA state. if (onData(slice, true)) { return Result.ASYNC; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 448efe3181e..aca43566ef5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -56,7 +56,8 @@ public class HeadersBodyParser extends BodyParser @Override public Result parse(ByteBuffer buffer) { - while (buffer.hasRemaining()) + boolean loop = false; + while (buffer.hasRemaining() || loop) { switch (state) { @@ -84,24 +85,25 @@ public class HeadersBodyParser extends BodyParser case PADDING_HIGH: { paddingLength = (buffer.get() & 0xFF) << 8; - length -= 1; + --length; + state = State.PADDING_LOW; if (length < 1 + 256) { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame_padding"); } - state = State.PADDING_LOW; break; } case PADDING_LOW: { paddingLength += buffer.get() & 0xFF; - length -= 1; - if (length < paddingLength) + --length; + length -= paddingLength; + state = hasFlag(Flag.PRIORITY) ? State.EXCLUSIVE : State.HEADERS; + loop = length == 0; + if (length < 0) { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame_padding"); } - length -= paddingLength; - state = hasFlag(Flag.PRIORITY) ? State.EXCLUSIVE : State.HEADERS; break; } case EXCLUSIVE: @@ -167,16 +169,11 @@ public class HeadersBodyParser extends BodyParser } case HEADERS: { - int blockLength = length - paddingLength; - if (blockLength < 0) - { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); - } - MetaData metaData = headerBlockParser.parse(buffer, blockLength); + MetaData metaData = headerBlockParser.parse(buffer, length); if (metaData != null) { - length -= blockLength; state = State.PADDING; + loop = paddingLength == 0; if (onHeaders(streamId, weight, exclusive, metaData)) { return Result.ASYNC; diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 2b7b1c47013..3d33542a889 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -25,6 +25,7 @@ import java.io.OutputStream; import java.net.Socket; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -36,6 +37,7 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; @@ -140,23 +142,7 @@ public class HTTP2ServerTest } }); - byte[] buffer = new byte[2048]; - InputStream input = client.getInputStream(); - client.setSoTimeout(1000); - while (true) - { - try - { - int read = input.read(buffer); - if (read <= 0) - throw new EOFException(); - parser.parse(ByteBuffer.wrap(buffer, 0, read)); - } - catch (SocketTimeoutException x) - { - break; - } - } + parseResponse(client, parser); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); @@ -166,4 +152,100 @@ public class HTTP2ServerTest Assert.assertEquals(200, responseMetaData.getStatus()); } } + + @Test + public void testRequestResponseContent() throws Exception + { + final byte[] content = "Hello, world!".getBytes(StandardCharsets.UTF_8); + final CountDownLatch latch = new CountDownLatch(4); + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + latch.countDown(); + resp.getOutputStream().write(content); + } + }); + + String host = "localhost"; + int port = connector.getLocalPort(); + HttpFields fields = new HttpFields(); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), + host + ":" + port, host, port, path, fields); + HeadersFrame request = new HeadersFrame(1, metaData, null, true); + Generator.LeaseCallback lease = generator.generate(request, Callback.Adapter.INSTANCE); + lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); + + try (Socket client = new Socket(host, port)) + { + OutputStream output = client.getOutputStream(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + output.write(BufferUtil.toArray(buffer)); + } + + final AtomicReference headersRef = new AtomicReference<>(); + final AtomicReference dataRef = new AtomicReference<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onSettings(SettingsFrame frame) + { + latch.countDown(); + return false; + } + + @Override + public boolean onHeaders(HeadersFrame frame) + { + headersRef.set(frame); + latch.countDown(); + return false; + } + + @Override + public boolean onData(DataFrame frame) + { + dataRef.set(frame); + latch.countDown(); + return false; + } + }); + + parseResponse(client, parser); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + + HeadersFrame response = headersRef.get(); + Assert.assertNotNull(response); + MetaData.Response responseMetaData = (MetaData.Response)response.getMetaData(); + Assert.assertEquals(200, responseMetaData.getStatus()); + + DataFrame responseData = dataRef.get(); + Assert.assertNotNull(responseData); + Assert.assertArrayEquals(content, BufferUtil.toArray(responseData.getData())); + } + } + + private void parseResponse(Socket client, Parser parser) throws IOException + { + byte[] buffer = new byte[2048]; + InputStream input = client.getInputStream(); + client.setSoTimeout(1000); + while (true) + { + try + { + int read = input.read(buffer); + if (read <= 0) + throw new EOFException(); + parser.parse(ByteBuffer.wrap(buffer, 0, read)); + } + catch (SocketTimeoutException x) + { + break; + } + } + } } From 7c5492acad5d69f010d0930587c75a6661132887 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 11 Jun 2014 08:56:23 +0200 Subject: [PATCH 053/269] Properly linking stream object with HEADERS frame. --- .../java/org/eclipse/jetty/http2/HTTP2Stream.java | 11 ++++++----- .../main/java/org/eclipse/jetty/http2/IStream.java | 3 +++ .../jetty/http2/server/HTTP2ServerSession.java | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 053591b6db2..51463d911f3 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -22,7 +22,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReference; -import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.util.Callback; @@ -31,23 +30,25 @@ public class HTTP2Stream implements IStream { private final AtomicReference> attributes = new AtomicReference<>(); private final ISession session; + private final HeadersFrame frame; private Listener listener; - public HTTP2Stream(ISession session) + public HTTP2Stream(ISession session, HeadersFrame frame) { this.session = session; + this.frame = frame; } @Override public int getId() { - return 0; + return frame.getStreamId(); } @Override - public Session getSession() + public ISession getSession() { - return null; + return session; } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index bc13bb9d268..47f7c802c2e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -23,6 +23,9 @@ import org.eclipse.jetty.http2.frames.DataFrame; public interface IStream extends Stream { + @Override + public ISession getSession(); + public void setListener(Listener listener); public boolean process(DataFrame frame); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index 45939982ea7..3af38f10d7a 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -60,7 +60,7 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis // TODO: handle duplicate streams // TODO: handle empty headers - IStream stream = new HTTP2Stream(this); + IStream stream = new HTTP2Stream(this, frame); IStream existing = putIfAbsent(stream); if (existing == null) { From 347324b71b314d77d2ba24f5f25c10c38634ce8f Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 11 Jun 2014 08:56:39 +0200 Subject: [PATCH 054/269] Improved logging. --- .../src/main/java/org/eclipse/jetty/http2/parser/Parser.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index abdb3156866..c5ab2b39415 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -94,6 +94,8 @@ public class Parser case BODY: { int type = headerParser.getFrameType(); + if (LOG.isDebugEnabled()) + LOG.debug("Parsing {} frame", FrameType.from(type)); if (type < 0 || type >= bodyParsers.length) { notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "unknown_frame_type_" + type); From 70223cbda9cb8a5575641050819c080c4b7d5a57 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 11 Jun 2014 10:23:29 +0200 Subject: [PATCH 055/269] add status 200 and method GET to ref set --- .../jetty/http2/hpack/HpackContext.java | 10 ++-- .../jetty/http2/hpack/HpackEncoder.java | 46 ++++++++++++------- .../jetty/http2/server/Http2Server.java | 1 - 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 58c4e13af67..c1afa1a676f 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -109,14 +109,14 @@ public class HpackContext private static final Map __staticFieldMap = new HashMap<>(); private static final Trie __staticNameMap = new ArrayTernaryTrie<>(true,512); - - private static final Entry[] __staticTable=new Entry[STATIC_TABLE.length]; + + private static final StaticEntry[] __staticTable=new StaticEntry[STATIC_TABLE.length]; static { Set added = new HashSet<>(); for (int i=1;i Date: Wed, 11 Jun 2014 15:16:40 +0200 Subject: [PATCH 056/269] Multiple mixed in changes and improvements Simplified HttpParser as per rfc7230 implemented local/remote hpack max table sizes --- .../client/http/HttpReceiverOverHTTP.java | 9 +- .../fcgi/parser/ResponseContentParser.java | 3 +- .../org/eclipse/jetty/http/BadMessage.java | 67 +++ .../eclipse/jetty/http/HostPortHttpField.java | 102 ++++ .../org/eclipse/jetty/http/HttpField.java | 13 + .../org/eclipse/jetty/http/HttpParser.java | 546 ++++++++---------- .../org/eclipse/jetty/http/HttpTester.java | 6 +- .../http/HttpGeneratorServerHTTPTest.java | 3 +- .../eclipse/jetty/http/HttpParserTest.java | 147 +++-- .../jetty/http2/hpack/AuthorityHttpField.java | 64 +- .../jetty/http2/hpack/HpackContext.java | 30 +- .../jetty/http2/hpack/HpackDecoder.java | 14 +- .../jetty/http2/hpack/HpackEncoder.java | 57 +- .../jetty/http2/hpack/MetaDataBuilder.java | 3 +- .../org/eclipse/jetty/server/HttpChannel.java | 6 +- .../jetty/server/HttpChannelOverHttp.java | 6 +- .../org/eclipse/jetty/server/RequestTest.java | 107 ---- .../server/proxy/ProxyHTTPSPDYConnection.java | 6 +- 18 files changed, 610 insertions(+), 579 deletions(-) create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index f98f4828942..34e586f5ee1 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -197,14 +197,11 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res } @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { HttpExchange exchange = getHttpExchange(); - if (exchange == null) - return false; - - responseHeader(exchange, field); - return false; + if (exchange != null) + responseHeader(exchange, field); } @Override diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java index 83a9a79ddb1..ef82e32fdfd 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java @@ -153,7 +153,7 @@ public class ResponseContentParser extends StreamContentParser } @Override - public boolean parsedHeader(HttpField httpField) + public void parsedHeader(HttpField httpField) { try { @@ -188,7 +188,6 @@ public class ResponseContentParser extends StreamContentParser { logger.debug("Exception while invoking listener " + listener, x); } - return false; } private void notifyBegin(int code, String reason) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java new file mode 100644 index 00000000000..c21beff3ce1 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java @@ -0,0 +1,67 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http; + +/* ------------------------------------------------------------------------------- */ +class BadMessage extends Error +{ + final int _code; + final String _reason; + + BadMessage() + { + this(400,null); + } + + BadMessage(int code) + { + this(code,null); + } + + BadMessage(String reason) + { + this(400,reason); + } + + BadMessage(int code,String reason) + { + _code=code; + _reason=reason; + } + + BadMessage(int code,String reason,Throwable cause) + { + super(cause); + _code=code; + _reason=reason; + } + + public int getCode() + { + return _code; + } + + public String getReason() + { + return _reason; + } + + +} \ No newline at end of file diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java new file mode 100644 index 00000000000..11c233cd4f7 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java @@ -0,0 +1,102 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http; + +import org.eclipse.jetty.util.StringUtil; + + + +/* ------------------------------------------------------------ */ +/** + */ +public class HostPortHttpField extends HttpField +{ + public final String _host; + public final int _port; + + public HostPortHttpField(HttpHeader header, String name, String authority) + { + super(header,name,authority); + + try + { + if (authority.charAt(0)=='[') + { + // ipv6reference + int close=authority.lastIndexOf(']'); + if (close<0) + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad ipv6"); + _host=authority.substring(1,close); + + if (authority.length()>close+1) + { + if (authority.charAt(close+1)!=':') + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad ipv6 port"); + _port=StringUtil.toInt(authority,close+2); + } + else + _port=0; + } + else + { + // ipv4address or hostname + int c = authority.lastIndexOf(':'); + if (c>=0) + { + _host=authority.substring(0,c); + _port=StringUtil.toInt(authority,c+1); + } + else + { + _host=authority; + _port=0; + } + } + } + catch (BadMessage bm) + { + throw bm; + } + catch(Exception e) + { + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad HostPort",e); + } + } + + /* ------------------------------------------------------------ */ + /** Get the host. + * @return the host + */ + public String getHost() + { + return _host; + } + + /* ------------------------------------------------------------ */ + /** Get the port. + * @return the port + */ + public int getPort() + { + return _port; + } + + +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index f270482f3a9..7cece45c30b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.http; +import org.eclipse.jetty.util.QuotedStringTokenizer; + /* ------------------------------------------------------------ */ /** A HTTP Field @@ -65,6 +67,17 @@ public class HttpField return _value; } + public String[] getValues() + { + QuotedStringTokenizer tok = new QuotedStringTokenizer(_value, ",", false, false); + tok.setSingle(false); + String[] v = new String[tok.countTokens()]; + int t=0; + while(tok.hasMoreTokens()) + v[t++]=tok.nextToken(); + return v; + } + @Override public String toString() { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index ac50f342de7..e0a7e9552c4 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -33,7 +33,7 @@ import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ -/** A Parser for 1.0 and 1.1 +/** A Parser for 1.0 and 1.1 as defined by RFC7230 *

* The is parser parses HTTP client and server messages from buffers * passed in the {@link #parseNext(ByteBuffer)} method. The parsed @@ -71,6 +71,8 @@ import org.eclipse.jetty.util.log.Logger; * fields. Otherwise a fast case insensitive string lookup is used that may alter the * case of the method and/or headers *

+ *

+ * @see http://tools.ietf.org/html/rfc7230 */ public class HttpParser { @@ -329,36 +331,6 @@ public class HttpParser return _state == state; } - /* ------------------------------------------------------------------------------- */ - private static class BadMessage extends Error - { - private static final long serialVersionUID = 1L; - private final int _code; - private final String _message; - - BadMessage() - { - this(400,null); - } - - BadMessage(int code) - { - this(code,null); - } - - BadMessage(String message) - { - this(400,message); - } - - BadMessage(int code,String message) - { - _code=code; - _message=message; - } - - } - /* ------------------------------------------------------------------------------- */ private byte next(ByteBuffer buffer) { @@ -781,124 +753,105 @@ public class HttpParser return handle; } - private boolean handleKnownHeaders(ByteBuffer buffer) + private void parsedHeader() { - boolean add_to_connection_trie=false; - switch (_header) + // handler last header if any. Delayed to here just in case there was a continuation line (above) + if (_headerString!=null || _valueString!=null) { - case CONTENT_LENGTH: - if (_endOfContent != EndOfContent.CHUNKED_CONTENT) + // Handle known headers + if (_header!=null) + { + boolean add_to_connection_trie=false; + switch (_header) { - try - { - _contentLength=Long.parseLong(_valueString); - } - catch(NumberFormatException e) - { - LOG.ignore(e); - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length"); - } - if (_contentLength <= 0) - _endOfContent=EndOfContent.NO_CONTENT; - else - _endOfContent=EndOfContent.CONTENT_LENGTH; - } - break; - - case TRANSFER_ENCODING: - if (_value==HttpHeaderValue.CHUNKED) - _endOfContent=EndOfContent.CHUNKED_CONTENT; - else - { - if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString())) - _endOfContent=EndOfContent.CHUNKED_CONTENT; - else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString())) - { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking"); - } - } - break; - - case HOST: - add_to_connection_trie=_connectionFields!=null && _field==null; - _host=true; - String host=_valueString; - int port=0; - if (host==null || host.length()==0) - { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header"); - } - - int len=host.length(); - loop: for (int i = len; i-- > 0;) - { - char c2 = (char)(0xff & host.charAt(i)); - switch (c2) - { - case ']': - break loop; - - case ':': + case CONTENT_LENGTH: + if (_endOfContent != EndOfContent.CHUNKED_CONTENT) + { try { - len=i; - port = StringUtil.toInt(host,i+1); + _contentLength=Long.parseLong(_valueString); } - catch (NumberFormatException e) + catch(NumberFormatException e) { - if (DEBUG) - LOG.debug(e); - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header"); + LOG.ignore(e); + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length"); } - break loop; - } - } - if (host.charAt(0)=='[') - { - if (host.charAt(len-1)!=']') - { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header"); - } - host = host.substring(1,len-1); - } - else if (len!=host.length()) - host = host.substring(0,len); - - if (_requestHandler!=null) - _requestHandler.parsedHostHeader(host,port); - - break; - - case CONNECTION: - // Don't cache if not persistent - if (_valueString!=null && _valueString.contains("close")) - { - _closed=true; - _connectionFields=null; - } - break; + if (_contentLength <= 0) + _endOfContent=EndOfContent.NO_CONTENT; + else + _endOfContent=EndOfContent.CONTENT_LENGTH; + } + break; - case AUTHORIZATION: - case ACCEPT: - case ACCEPT_CHARSET: - case ACCEPT_ENCODING: - case ACCEPT_LANGUAGE: - case COOKIE: - case CACHE_CONTROL: - case USER_AGENT: - add_to_connection_trie=_connectionFields!=null && _field==null; - break; - - default: break; - } - - if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null) - { - _field=new HttpField(_header,_valueString); - _connectionFields.put(_field); + case TRANSFER_ENCODING: + if (_value==HttpHeaderValue.CHUNKED) + _endOfContent=EndOfContent.CHUNKED_CONTENT; + else + { + if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString())) + _endOfContent=EndOfContent.CHUNKED_CONTENT; + else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString())) + { + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking"); + } + } + break; + + case HOST: + _host=true; + HostPortHttpField hpfield; + if (_field!=null) + { + hpfield = (HostPortHttpField)_field; + } + else + { + _field=hpfield=new HostPortHttpField(_header,_strict?_headerString:_header.asString(),_valueString); + add_to_connection_trie=_connectionFields!=null; + } + + if (_requestHandler!=null) + _requestHandler.parsedHostHeader(hpfield.getHost(),hpfield.getPort()); + + break; + + case CONNECTION: + // Don't cache if not persistent + if (_valueString!=null && _valueString.contains("close")) + { + _closed=true; + _connectionFields=null; + } + break; + + case AUTHORIZATION: + case ACCEPT: + case ACCEPT_CHARSET: + case ACCEPT_ENCODING: + case ACCEPT_LANGUAGE: + case COOKIE: + case CACHE_CONTROL: + case USER_AGENT: + add_to_connection_trie=_connectionFields!=null && _field==null; + break; + + default: break; + } + + if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null) + { + if (_field==null) + _field=new HttpField(_header,_strict?_headerString:_header.asString(),_valueString); + _connectionFields.put(_field); + } + } + _handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString)); } - return false; + _headerString=_valueString=null; + _header=null; + _value=null; + _field=null; } @@ -932,194 +885,160 @@ public class HttpParser case HttpTokens.COLON: case HttpTokens.SPACE: case HttpTokens.TAB: + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Continuation"); + + case HttpTokens.LINE_FEED: { - // header value without name - continuation? - if (_valueString==null) + _contentPosition=0; + + // End of headers! + + // Was there a required host header? + if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null) { - _string.setLength(0); - _length=0; + throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host"); } - else + + // is it a response that cannot have a body? + if (_responseHandler !=null && // response + (_responseStatus == 304 || // not-modified response + _responseStatus == 204 || // no-content response + _responseStatus < 200)) // 1xx response + _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set + + // else if we don't know framing + else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) { - setString(_valueString); - _string.append(' '); - _length++; - _valueString=null; + if (_responseStatus == 0 // request + || _responseStatus == 304 // not-modified response + || _responseStatus == 204 // no-content response + || _responseStatus < 200) // 1xx response + _endOfContent=EndOfContent.NO_CONTENT; + else + _endOfContent=EndOfContent.EOF_CONTENT; + } + + // How is the message ended? + switch (_endOfContent) + { + case EOF_CONTENT: + setState(State.EOF_CONTENT); + handle=_handler.headerComplete()||handle; + break; + + case CHUNKED_CONTENT: + setState(State.CHUNKED_CONTENT); + handle=_handler.headerComplete()||handle; + break; + + case NO_CONTENT: + handle=_handler.headerComplete()||handle; + setState(State.END); + handle=_handler.messageComplete()||handle; + break; + + default: + setState(State.CONTENT); + handle=_handler.headerComplete()||handle; + break; } - setState(State.HEADER_VALUE); break; } default: { - // handler last header if any. Delayed to here just in case there was a continuation line (above) - if (_headerString!=null || _valueString!=null) - { - // Handle known headers - if (_header!=null && handleKnownHeaders(buffer)) - { - _headerString=_valueString=null; - _header=null; - _value=null; - _field=null; - return true; - } - handle=_handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString))||handle; - } - _headerString=_valueString=null; - _header=null; - _value=null; - _field=null; - // now handle the ch - if (ch == HttpTokens.LINE_FEED) - { - _contentPosition=0; - - // End of headers! - - // Was there a required host header? - if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null) - { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host"); - } - - // is it a response that cannot have a body? - if (_responseHandler !=null && // response - (_responseStatus == 304 || // not-modified response - _responseStatus == 204 || // no-content response - _responseStatus < 200)) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set - - // else if we don't know framing - else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) - { - if (_responseStatus == 0 // request - || _responseStatus == 304 // not-modified response - || _responseStatus == 204 // no-content response - || _responseStatus < 200) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; - else - _endOfContent=EndOfContent.EOF_CONTENT; - } - - // How is the message ended? - switch (_endOfContent) - { - case EOF_CONTENT: - setState(State.EOF_CONTENT); - handle=_handler.headerComplete()||handle; - break; - - case CHUNKED_CONTENT: - setState(State.CHUNKED_CONTENT); - handle=_handler.headerComplete()||handle; - break; - - case NO_CONTENT: - handle=_handler.headerComplete()||handle; - setState(State.END); - handle=_handler.messageComplete()||handle; - break; - - default: - setState(State.CONTENT); - handle=_handler.headerComplete()||handle; - break; - } - } - else if (ch<=HttpTokens.SPACE) + if (ch<=HttpTokens.SPACE) throw new BadMessage(); - else - { - if (buffer.hasRemaining()) - { - // Try a look ahead for the known header name and value. - HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining()); - if (field==null) - field=CACHE.getBest(buffer,-1,buffer.remaining()); - - if (field!=null) - { - final String n; - final String v; - if (_strict) - { - // Have to get the fields exactly from the buffer to match case - String fn=field.getName(); - String fv=field.getValue(); - n=BufferUtil.toString(buffer,buffer.position()-1,fn.length(),StandardCharsets.US_ASCII); - if (fv==null) - v=null; - else - { - v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1); - field=new HttpField(field.getHeader(),n,v); - } - } + if (buffer.hasRemaining()) + { + // Try a look ahead for the known header name and value. + HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining()); + if (field==null) + field=CACHE.getBest(buffer,-1,buffer.remaining()); + + if (field!=null) + { + final String n; + final String v; + + if (_strict) + { + // Have to get the fields exactly from the buffer to match case + String fn=field.getName(); + String fv=field.getValue(); + n=BufferUtil.toString(buffer,buffer.position()-1,fn.length(),StandardCharsets.US_ASCII); + if (fv==null) + v=null; else { - n=field.getName(); - v=field.getValue(); + v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1); + field=new HttpField(field.getHeader(),n,v); } - - _header=field.getHeader(); - _headerString=n; - - if (v==null) - { - // Header only - setState(State.HEADER_VALUE); - _string.setLength(0); - _length=0; - buffer.position(buffer.position()+n.length()+1); + } + else + { + n=field.getName(); + v=field.getValue(); + } + + _header=field.getHeader(); + _headerString=n; + + if (v==null) + { + // Header only + setState(State.HEADER_VALUE); + _string.setLength(0); + _length=0; + buffer.position(buffer.position()+n.length()+1); + break; + } + else + { + // Header and value + int pos=buffer.position()+n.length()+v.length()+1; + byte b=buffer.get(pos); + + if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED) + { + _field=field; + _valueString=v; + setState(State.HEADER_IN_VALUE); + + if (b==HttpTokens.CARRIAGE_RETURN) + { + _cr=true; + buffer.position(pos+1); + } + else + buffer.position(pos); break; } else { - // Header and value - int pos=buffer.position()+n.length()+v.length()+1; - byte b=buffer.get(pos); - - if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED) - { - _field=field; - _valueString=v; - setState(State.HEADER_IN_VALUE); - - if (b==HttpTokens.CARRIAGE_RETURN) - { - _cr=true; - buffer.position(pos+1); - } - else - buffer.position(pos); - break; - } - else - { - setState(State.HEADER_IN_VALUE); - setString(v); - buffer.position(pos); - break; - } + setState(State.HEADER_IN_VALUE); + setString(v); + buffer.position(pos); + break; } } } - - // New header - setState(State.HEADER_IN_NAME); - _string.setLength(0); - _string.append((char)ch); - _length=1; } + + // New header + setState(State.HEADER_IN_NAME); + _string.setLength(0); + _string.append((char)ch); + _length=1; + } } break; case HEADER_IN_NAME: - if (ch==HttpTokens.COLON || ch==HttpTokens.LINE_FEED) + if (ch==HttpTokens.COLON) { if (_headerString==null) { @@ -1128,11 +1047,11 @@ public class HttpParser } _length=-1; - setState(ch==HttpTokens.LINE_FEED?State.HEADER:State.HEADER_VALUE); + setState(State.HEADER_VALUE); break; } - if (ch>=HttpTokens.SPACE || ch==HttpTokens.TAB) + if (ch>HttpTokens.SPACE) { if (_header!=null) { @@ -1160,19 +1079,8 @@ public class HttpParser if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB) break; - - if (ch==HttpTokens.LINE_FEED) - { - if (_length > 0) - { - _value=null; - _valueString=(_valueString==null)?takeString():(_valueString+" "+takeString()); - } - setState(State.HEADER); - break; - } - throw new BadMessage("Illegal character"); + throw new BadMessage(); case HEADER_IN_VALUE: if (ch>=HttpTokens.SPACE || ch<0 || ch==HttpTokens.TAB) @@ -1197,6 +1105,7 @@ public class HttpParser _valueString=takeString(); _length=-1; } + parsedHeader(); setState(State.HEADER); break; } @@ -1332,11 +1241,11 @@ public class HttpParser { BufferUtil.clear(buffer); - LOG.warn("badMessage: "+e._code+(e._message!=null?" "+e._message:"")+" for "+_handler); + LOG.warn("badMessage: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler); if (DEBUG) LOG.debug(e); setState(State.CLOSED); - _handler.badMessage(e._code, e._message); + _handler.badMessage(e.getCode(), e.getReason()); return false; } catch(Exception e) @@ -1609,10 +1518,9 @@ public class HttpParser /** * This is the method called by parser when a HTTP Header name and value is found * @param field The field parsed - * @return True if the parser should return to its caller */ - public boolean parsedHeader(HttpField field); - + public void parsedHeader(HttpField field); + /* ------------------------------------------------------------ */ /** Called to signal that an EOF was received unexpectedly * during the parsing of a HTTP message @@ -1648,14 +1556,14 @@ public class HttpParser * @param version * @return true if handling parsing should return. */ - public abstract boolean startRequest(String method, HttpURI uri, HttpVersion version); + public boolean startRequest(String method, HttpURI uri, HttpVersion version); /** * This is the method called by the parser after it has parsed the host header (and checked it's format). This is * called after the {@link HttpHandler#parsedHeader(HttpField)} methods and before * HttpHandler#headerComplete(); */ - public abstract boolean parsedHostHeader(String host,int port); + public void parsedHostHeader(String host,int port); } public interface ResponseHandler extends HttpHandler @@ -1663,7 +1571,7 @@ public class HttpParser /** * This is the method called by parser when the HTTP request line is parsed */ - public abstract boolean startResponse(HttpVersion version, int status, String reason); + public boolean startResponse(HttpVersion version, int status, String reason); } public Trie getFieldCache() diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java index 0385ffcb7e7..a7f081e76af 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java @@ -132,10 +132,9 @@ public class HttpTester } } @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { put(field.getName(),field.getValue()); - return false; } @Override @@ -302,9 +301,8 @@ public class HttpTester } @Override - public boolean parsedHostHeader(String host,int port) + public void parsedHostHeader(String host,int port) { - return false; } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java index 2925f3e41f2..5fc8436bfb9 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java @@ -247,9 +247,8 @@ public class HttpGeneratorServerHTTPTest } @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { - return false; } @Override diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 12b2b389087..8b25973d8c8 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -181,6 +181,73 @@ public class HttpParserTest assertEquals("close", _val[1]); assertEquals(1, _headers); } + + @Test + public void test7230NoContinuations() throws Exception + { + ByteBuffer buffer= BufferUtil.toBuffer( + "GET / HTTP/1.0\015\012" + + "Host: localhost\015\012" + + "Name: value\015\012" + + " extra\015\012" + + "\015\012"); + + HttpParser.RequestHandler handler = new Handler(); + HttpParser parser= new HttpParser(handler); + parseAll(parser,buffer); + + Assert.assertThat(_bad,Matchers.notNullValue()); + Assert.assertThat(_bad,Matchers.containsString("Bad Continuation")); + } + + + @Test + public void test7230NoWhiteSpaceInName() throws Exception + { + ByteBuffer buffer= BufferUtil.toBuffer( + "GET / HTTP/1.0\015\012" + + "Host: localhost\015\012" + + " Name: value\015\012" + + "\015\012"); + + HttpParser.RequestHandler handler = new Handler(); + HttpParser parser= new HttpParser(handler); + parseAll(parser,buffer); + + Assert.assertThat(_bad,Matchers.notNullValue()); + Assert.assertThat(_bad,Matchers.containsString("Bad")); + + init(); + buffer= BufferUtil.toBuffer( + "GET / HTTP/1.0\015\012" + + "Host: localhost\015\012" + + "N ame: value\015\012" + + "\015\012"); + + handler = new Handler(); + parser= new HttpParser(handler); + parseAll(parser,buffer); + + Assert.assertThat(_bad,Matchers.containsString("Illegal character")); + + + init(); + buffer= BufferUtil.toBuffer( + "GET / HTTP/1.0\015\012" + + "Host: localhost\015\012" + + "Name : value\015\012" + + "\015\012"); + + handler = new Handler(); + parser= new HttpParser(handler); + parseAll(parser,buffer); + + Assert.assertThat(_bad,Matchers.containsString("Illegal character")); + + } + + + @Test public void testHeaderParseDirect() throws Exception @@ -189,13 +256,11 @@ public class HttpParserTest "GET / HTTP/1.0\015\012" + "Host: localhost\015\012" + "Header1: value1\015\012" + - "Header 2 : value 2a \015\012" + - " value 2b \015\012" + - "Header3: \015\012" + - "Header4 \015\012" + - " value4\015\012" + - "Server5 : notServer\015\012" + - "Host Header: notHost\015\012" + + "Header2: value 2a \015\012" + + "Header3: 3\015\012" + + "Header4:value4\015\012" + + "Server5: notServer\015\012" + + "HostHeader: notHost\015\012" + "Connection: close\015\012" + "Accept-Encoding: gzip, deflated\015\012" + "Accept: unknown\015\012" + @@ -216,15 +281,15 @@ public class HttpParserTest assertEquals("localhost", _val[0]); assertEquals("Header1", _hdr[1]); assertEquals("value1", _val[1]); - assertEquals("Header 2", _hdr[2]); - assertEquals("value 2a value 2b", _val[2]); + assertEquals("Header2", _hdr[2]); + assertEquals("value 2a", _val[2]); assertEquals("Header3", _hdr[3]); - assertEquals(null, _val[3]); + assertEquals("3", _val[3]); assertEquals("Header4", _hdr[4]); assertEquals("value4", _val[4]); assertEquals("Server5", _hdr[5]); assertEquals("notServer", _val[5]); - assertEquals("Host Header", _hdr[6]); + assertEquals("HostHeader", _hdr[6]); assertEquals("notHost", _val[6]); assertEquals("Connection", _hdr[7]); assertEquals("close", _val[7]); @@ -242,13 +307,11 @@ public class HttpParserTest "GET / HTTP/1.0\015\012" + "Host: localhost\015\012" + "Header1: value1\015\012" + - "Header 2 : value 2a \015\012" + - " value 2b \015\012" + - "Header3: \015\012" + - "Header4 \015\012" + - " value4\015\012" + - "Server5 : notServer\015\012" + - "Host Header: notHost\015\012" + + "Header2: value 2a \015\012" + + "Header3: 3\015\012" + + "Header4:value4\015\012" + + "Server5: notServer\015\012" + + "HostHeader: notHost\015\012" + "Connection: close\015\012" + "Accept-Encoding: gzip, deflated\015\012" + "Accept: unknown\015\012" + @@ -264,15 +327,15 @@ public class HttpParserTest assertEquals("localhost", _val[0]); assertEquals("Header1", _hdr[1]); assertEquals("value1", _val[1]); - assertEquals("Header 2", _hdr[2]); - assertEquals("value 2a value 2b", _val[2]); + assertEquals("Header2", _hdr[2]); + assertEquals("value 2a", _val[2]); assertEquals("Header3", _hdr[3]); - assertEquals(null, _val[3]); + assertEquals("3", _val[3]); assertEquals("Header4", _hdr[4]); assertEquals("value4", _val[4]); assertEquals("Server5", _hdr[5]); assertEquals("notServer", _val[5]); - assertEquals("Host Header", _hdr[6]); + assertEquals("HostHeader", _hdr[6]); assertEquals("notHost", _val[6]); assertEquals("Connection", _hdr[7]); assertEquals("close", _val[7]); @@ -292,13 +355,11 @@ public class HttpParserTest "GET / HTTP/1.0\n" + "Host: localhost\n" + "Header1: value1\n" + - "Header 2 : value 2a \n" + - " value 2b \n" + - "Header3: \n" + - "Header4 \n" + - " value4\n" + - "Server5 : notServer\n" + - "Host Header: notHost\n" + + "Header2: value 2a value 2b \n" + + "Header3: 3\n" + + "Header4:value4\n" + + "Server5: notServer\n" + + "HostHeader: notHost\n" + "Connection: close\n" + "Accept-Encoding: gzip, deflated\n" + "Accept: unknown\n" + @@ -314,15 +375,15 @@ public class HttpParserTest assertEquals("localhost", _val[0]); assertEquals("Header1", _hdr[1]); assertEquals("value1", _val[1]); - assertEquals("Header 2", _hdr[2]); + assertEquals("Header2", _hdr[2]); assertEquals("value 2a value 2b", _val[2]); assertEquals("Header3", _hdr[3]); - assertEquals(null, _val[3]); + assertEquals("3", _val[3]); assertEquals("Header4", _hdr[4]); assertEquals("value4", _val[4]); assertEquals("Server5", _hdr[5]); assertEquals("notServer", _val[5]); - assertEquals("Host Header", _hdr[6]); + assertEquals("HostHeader", _hdr[6]); assertEquals("notHost", _val[6]); assertEquals("Connection", _hdr[7]); assertEquals("close", _val[7]); @@ -496,11 +557,9 @@ public class HttpParserTest "XXXXSPLIT / HTTP/1.0\015\012" + "Host: localhost\015\012" + "Header1: value1\015\012" + - "Header2 : value 2a \015\012" + - " value 2b \015\012" + - "Header3: \015\012" + - "Header4 \015\012" + - " value4\015\012" + + "Header2: value 2a \015\012" + + "Header3: 3\015\012" + + "Header4:value4\015\012" + "Server5: notServer\015\012" + "\015\012ZZZZ"); buffer.position(2); @@ -534,9 +593,9 @@ public class HttpParserTest assertEquals("Header1", _hdr[1]); assertEquals("value1", _val[1]); assertEquals("Header2", _hdr[2]); - assertEquals("value 2a value 2b", _val[2]); + assertEquals("value 2a", _val[2]); assertEquals("Header3", _hdr[3]); - assertEquals(null, _val[3]); + assertEquals("3", _val[3]); assertEquals("Header4", _hdr[4]); assertEquals("value4", _val[4]); assertEquals("Server5", _hdr[5]); @@ -1305,7 +1364,7 @@ public class HttpParserTest HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); - assertEquals("Bad IPv6 Host header",_bad); + Assert.assertThat(_bad,Matchers.containsString("Bad")); } @Test @@ -1336,7 +1395,7 @@ public class HttpParserTest HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); - assertEquals("Bad Host header",_bad); + Assert.assertThat(_bad,Matchers.containsString("Bad Host")); } @Test @@ -1517,21 +1576,19 @@ public class HttpParserTest } @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { _fields.add(field); //System.err.println("header "+name+": "+value); _hdr[++_headers]= field.getName(); _val[_headers]= field.getValue(); - return false; } @Override - public boolean parsedHostHeader(String host,int port) + public void parsedHostHeader(String host,int port) { _host=host; _port=port; - return false; } @Override diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java index e845f1426f6..121788b66cb 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java @@ -19,76 +19,20 @@ package org.eclipse.jetty.http2.hpack; -import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HostPortHttpField; +import org.eclipse.jetty.http2.hpack.HpackContext; import org.eclipse.jetty.util.StringUtil; /* ------------------------------------------------------------ */ /** */ -public class AuthorityHttpField extends HttpField +public class AuthorityHttpField extends HostPortHttpField { public final static String AUTHORITY = HpackContext.STATIC_TABLE[1][0]; - public final String _host; - public final int _port; - public AuthorityHttpField(String authority) { - super(AUTHORITY,authority); - - if (authority.charAt(0)=='[') - { - // ipv6reference - int close=authority.indexOf(']'); - if (close<0) - throw new IllegalArgumentException("Bad ipv6"); - _host=authority.substring(1,close-1); - - if (authority.length()>close+1) - { - if (authority.charAt(close+1)!=':') - throw new IllegalArgumentException("Bad ipv6 port"); - _port=StringUtil.toInt(authority,close+2); - - } - else - _port=0; - } - else - { - // ipv4address or hostname - int c = authority.lastIndexOf(':'); - if (c>=0) - { - _host=authority.substring(0,c); - _port=StringUtil.toInt(authority,c+1); - } - else - { - _host=authority; - _port=0; - } - } + super(null,AUTHORITY,authority); } - - /* ------------------------------------------------------------ */ - /** Get the host. - * @return the host - */ - public String getHost() - { - return _host; - } - - /* ------------------------------------------------------------ */ - /** Get the port. - * @return the port - */ - public int getPort() - { - return _port; - } - - } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index c1afa1a676f..4b2eb4a8e2f 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -187,11 +187,11 @@ public class HpackContext _headerTable=new HeaderTable(guesstimateEntries,guesstimateEntries+10); } - public void resize(int maxHeaderTableSize) + public void resize(int newMaxHeaderTableSize) { - LOG.debug("HdrTbl resized {}",maxHeaderTableSize); - _maxHeaderTableSizeInBytes=maxHeaderTableSize; - int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10); + LOG.debug("HdrTbl resized {}",newMaxHeaderTableSize); + _maxHeaderTableSizeInBytes=newMaxHeaderTableSize; + int guesstimateEntries = 10+newMaxHeaderTableSize/(32+10+10); evict(); _headerTable.resizeUnsafe(guesstimateEntries); } @@ -245,11 +245,30 @@ public class HpackContext return entry; } - public Object size() + /** + * @return Current Header table size in entries + */ + public int size() { return _headerTable.size(); } + /** + * @return Current Header table size in Octets + */ + public int getHeaderTableSize() + { + return _headerTableSizeInBytes; + } + + /** + * @return Max Header table size in Octets + */ + public int getMaxHeaderTableSize() + { + return _maxHeaderTableSizeInBytes; + } + public int index(Entry entry) { if (entry._index<0) @@ -575,4 +594,5 @@ public class HpackContext } } + } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 2ecb070ff09..a31df90c158 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; @@ -41,15 +42,22 @@ public class HpackDecoder private final HpackContext _context; private final MetaDataBuilder _builder = new MetaDataBuilder(); + private int _localMaxHeaderTableSize; public HpackDecoder() { this(4096); } - public HpackDecoder(int maxHeaderTableSize) + public HpackDecoder(int localMaxHeaderTableSize) { - _context=new HpackContext(maxHeaderTableSize); + _context=new HpackContext(localMaxHeaderTableSize); + _localMaxHeaderTableSize=localMaxHeaderTableSize; + } + + public void setLocalMaxHeaderTableSize(int localMaxHeaderTableSize) + { + _localMaxHeaderTableSize=localMaxHeaderTableSize; } public MetaData decode(ByteBuffer buffer) @@ -188,6 +196,8 @@ public class HpackDecoder int size = NBitInteger.decode(buffer,4); if (LOG.isDebugEnabled()) LOG.debug("decode resize="+size); + if (size>_localMaxHeaderTableSize) + throw new IllegalArgumentException(); _context.resize(size); } else if (f==3) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index ac21d4ce359..42e912d6181 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -75,16 +75,24 @@ public class HpackEncoder } private final HpackContext _context; + private int _remoteMaxHeaderTableSize; + private int _localMaxHeaderTableSize; - public HpackEncoder() { - this(4096); + this(4096,4096); } - public HpackEncoder(int maxHeaderTableSize) + public HpackEncoder(int localMaxHeaderTableSize) { - _context=new HpackContext(maxHeaderTableSize); + this(localMaxHeaderTableSize,4096); + } + + public HpackEncoder(int localMaxHeaderTableSize,int remoteMaxHeaderTableSize) + { + _context=new HpackContext(remoteMaxHeaderTableSize); + _remoteMaxHeaderTableSize=remoteMaxHeaderTableSize; + _localMaxHeaderTableSize=localMaxHeaderTableSize; } public HpackContext getContext() @@ -92,6 +100,16 @@ public class HpackEncoder return _context; } + public void setRemoteMaxHeaderTableSize(int remoteMaxHeaderTableSize) + { + _remoteMaxHeaderTableSize=remoteMaxHeaderTableSize; + } + + public void setLocalMaxHeaderTableSize(int localMaxHeaderTableSize) + { + _localMaxHeaderTableSize=localMaxHeaderTableSize; + } + public void encode(MetaData metadata,Lease lease) { ByteBuffer buffer = lease.acquire(8*1024,false); // TODO make size configurable @@ -102,21 +120,15 @@ public class HpackEncoder BufferUtil.flipToFlush(buffer,0); } - public void encodeMaxHeaderTableSize(ByteBuffer buffer, int maxHeaderTableSize) - { - _context.resize(maxHeaderTableSize); - } - - public void encodeClearReferenceSet(ByteBuffer buffer) - { - // TODO - _context.clearReferenceSet(); - } public void encode(ByteBuffer buffer, MetaData metadata) { - // Add Request/response meta fields + // Check the header table sizes! + int maxHeaderTableSize=Math.min(_remoteMaxHeaderTableSize,_localMaxHeaderTableSize); + if (maxHeaderTableSize!=_context.getMaxHeaderTableSize()) + encodeMaxHeaderTableSize(buffer,maxHeaderTableSize); + // Add Request/response meta fields if (metadata.isRequest()) { MetaData.Request request = (MetaData.Request)metadata; @@ -147,6 +159,21 @@ public class HpackEncoder _context.removedUnusedReferences(buffer); } + public void encodeMaxHeaderTableSize(ByteBuffer buffer, int maxHeaderTableSize) + { + if (maxHeaderTableSize>_remoteMaxHeaderTableSize) + throw new IllegalArgumentException(); + buffer.put((byte)0x20); + NBitInteger.encode(buffer,4,maxHeaderTableSize); + _context.resize(maxHeaderTableSize); + } + + public void encodeClearReferenceSet(ByteBuffer buffer) + { + buffer.put((byte)0x30); + _context.clearReferenceSet(); + } + private void encode(ByteBuffer buffer, HttpField field) { final int p=LOG.isDebugEnabled()?buffer.position():-1; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 6657c7899eb..49066b91b50 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -22,6 +22,7 @@ package org.eclipse.jetty.http2.hpack; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; @@ -83,7 +84,7 @@ public class MetaDataBuilder case ":authority": _authority=field.getValue(); - AuthorityHttpField afield=(field instanceof AuthorityHttpField)?((AuthorityHttpField)field):new AuthorityHttpField(field.getValue()); + HostPortHttpField afield=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); _host=afield.getHost(); _port=afield.getPort(); break; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 09e92923581..e1e55e30c78 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -499,7 +499,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable } @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { HttpHeader header=field.getHeader(); String value=field.getValue(); @@ -521,18 +521,16 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable if (field.getName()!=null) _request.getHttpFields().add(field); - return false; } @Override - public boolean parsedHostHeader(String host, int port) + public void parsedHostHeader(String host, int port) { if (_request.getUri().getHost()==null) { _request.setServerName(host); _request.setServerPort(port); } - return false; } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index bede165bcf9..a041f52582c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -95,7 +95,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. @Override - public boolean parsedHeader(HttpField field) + public void parsedHeader(HttpField field) { HttpHeader header=field.getHeader(); String value=field.getValue(); @@ -113,7 +113,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. break; default: - String[] values = value.split(","); + String[] values = field.getValues(); for (int i = 0; values != null && i < values.length; i++) { expect = HttpHeaderValue.CACHE.get(values[i].trim()); @@ -136,7 +136,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. } } } - return super.parsedHeader(field); + super.parsedHeader(field); } /** diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 17e1ec9af97..294c5ffc220 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -128,41 +128,6 @@ public class RequestTest } - @Test - public void testEmptyHeaders() throws Exception - { - _handler._checker = new RequestTester() - { - @Override - public boolean check(HttpServletRequest request,HttpServletResponse response) - { - assertNotNull(request.getLocale()); - assertTrue(request.getLocales().hasMoreElements()); - assertNull(request.getContentType()); - assertNull(request.getCharacterEncoding()); - assertEquals(0,request.getQueryString().length()); - assertEquals(-1,request.getContentLength()); - assertNull(request.getCookies()); - assertNull(request.getHeader("Name")); - assertFalse(request.getHeaders("Name").hasMoreElements()); - assertEquals(-1,request.getDateHeader("Name")); - return true; - } - }; - - String request="GET /? HTTP/1.1\r\n"+ - "Host: whatever\r\n"+ - "Connection: close\n"+ - "Content-Type: \n"+ - "Accept-Language: \n"+ - "Cookie: \n"+ - "Name: \n"+ - "\n"; - - String responses=_connector.getResponses(request); - assertTrue(responses.startsWith("HTTP/1.1 200")); - } - @Test public void testMultiPartNoConfig() throws Exception { @@ -1058,78 +1023,6 @@ public class RequestTest } - @Test - public void testCookieLeak() throws Exception - { - final String[] cookie=new String[10]; - - _handler._checker = new RequestTester() - { - @Override - public boolean check(HttpServletRequest request,HttpServletResponse response) - { - for (int i=0;i Date: Wed, 11 Jun 2014 16:53:17 +0200 Subject: [PATCH 057/269] convert MetaData to HttpField as a list --- .../org/eclipse/jetty/http/HttpField.java | 138 +++++++++++++++++- .../org/eclipse/jetty/http/HttpFields.java | 130 ++++++----------- .../eclipse/jetty/http/HttpFieldsTest.java | 28 ++++ .../eclipse/jetty/http2/hpack/MetaData.java | 24 +-- .../jetty/http2/hpack/MetaDataBuilder.java | 15 +- 5 files changed, 216 insertions(+), 119 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index 7cece45c30b..d24fff8770c 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.http; +import java.util.ArrayList; + import org.eclipse.jetty.util.QuotedStringTokenizer; @@ -68,14 +70,136 @@ public class HttpField } public String[] getValues() + { + ArrayList list = new ArrayList<>(); + int state = 0; + int start=0; + int end=0; + StringBuilder builder = new StringBuilder(); + + for (int i=0;i<_value.length();i++) + { + char c = _value.charAt(i); + switch(state) + { + case 0: // initial white space + switch(c) + { + case '"': // open quote + state=2; + break; + + case ',': // leading empty field + list.add(""); + break; + + case ' ': // more white space + case '\t': + break; + + default: // character + start=i; + end=i; + state=1; + } + break; + + case 1: // In token + switch(c) + { + case ',': // next field + list.add(_value.substring(start,end+1)); + state=0; + break; + + case ' ': // more white space + case '\t': + break; + + default: + end=i; + } + break; + + case 2: // In Quoted + switch(c) + { + case '\\': // next field + state=3; + break; + + case '"': // end quote + list.add(builder.toString()); + builder.setLength(0); + state=4; + break; + + default: + builder.append(c); + } + break; + + case 3: // In Quoted Quoted + builder.append(c); + state=2; + break; + + case 4: // WS after end quote + switch(c) + { + case ' ': // white space + case '\t': // white space + break; + + case ',': // white space + state=0; + break; + + default: + throw new IllegalArgumentException("c="+(int)c); + + } + break; + } + } + + switch(state) + { + case 0: + break; + case 1: + list.add(_value.substring(start,end+1)); + break; + case 4: + break; + + default: + throw new IllegalArgumentException("state="+state); + } + + return list.toArray(new String[list.size()]); + } + + /* ------------------------------------------------------------ */ + /** Look for a value in a possible multi valued field + * @param value + * @return True iff the value is contained in the field value entirely or + * as an element of a quoted comma separated list + */ + public boolean contains(String value) { - QuotedStringTokenizer tok = new QuotedStringTokenizer(_value, ",", false, false); - tok.setSingle(false); - String[] v = new String[tok.countTokens()]; - int t=0; - while(tok.hasMoreTokens()) - v[t++]=tok.nextToken(); - return v; + if (_value==null) + return value==null; + + if (_value.equalsIgnoreCase(value)) + return true; + + String[] values = getValues(); + for (String v:values) + if (v.equalsIgnoreCase(value)) + return true; + + return false; } @Override diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 8de9f5f6e83..b9031cdb276 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -24,13 +24,11 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.StringTokenizer; -import java.util.regex.Pattern; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.LazyList; @@ -50,28 +48,34 @@ import org.eclipse.jetty.util.log.Logger; *

The cookie handling provided by this class is guided by the Servlet specification and RFC6265. * */ -public class HttpFields implements Iterable +public class HttpFields extends ArrayList { - private static final Logger LOG = Log.getLogger(HttpFields.class); - private final static Pattern __splitter = Pattern.compile("\\s*,\\s*"); + private static final long serialVersionUID = 1L; + private static final Logger LOG = Log.getLogger(HttpFields.class); public final static String __separators = ", \t"; - private final ArrayList _fields = new ArrayList<>(20); - /** * Constructor. */ public HttpFields() { } + + /** + * Constructor. + */ + public HttpFields(int capacity) + { + super(capacity); + } /** * Get Collection of header names. */ public Collection getFieldNamesCollection() { - final Set list = new HashSet<>(_fields.size()); - for (HttpField f : _fields) + final Set list = new HashSet<>(size()); + for (HttpField f : this) { if (f!=null) list.add(f.getName()); @@ -88,11 +92,6 @@ public class HttpFields implements Iterable return Collections.enumeration(getFieldNamesCollection()); } - public int size() - { - return _fields.size(); - } - /** * Get a Field by index. * @return A Field value or null if the Field value has not been set @@ -100,20 +99,14 @@ public class HttpFields implements Iterable */ public HttpField getField(int i) { - return _fields.get(i); - } - - @Override - public Iterator iterator() - { - return _fields.iterator(); + return get(i); } public HttpField getField(HttpHeader header) { - for (int i=0;i<_fields.size();i++) + for (int i=0;i public HttpField getField(String name) { - for (int i=0;i<_fields.size();i++) + for (int i=0;i public boolean contains(HttpHeader header, String value) { - for (int i=0;i<_fields.size();i++) + for (int i=0;i public boolean contains(String name, String value) { - for (int i=0;i<_fields.size();i++) + for (int i=0;i public List getValuesList(String name) { final List list = new ArrayList<>(); - for (HttpField f : _fields) + for (HttpField f : this) if (f.getName().equalsIgnoreCase(name)) list.add(f.getValue()); return list; @@ -232,9 +207,9 @@ public class HttpFields implements Iterable */ public Enumeration getValues(final String name) { - for (int i=0;i<_fields.size();i++) + for (int i=0;i { if (field==null) { - while (i<_fields.size()) + while (i public void put(HttpField field) { boolean put=false; - for (int i=_fields.size();i-->0;) + for (int i=size();i-->0;) { - HttpField f=_fields.get(i); + HttpField f=get(i); if (f.isSameName(field)) { if (put) - _fields.remove(i); + remove(i); else { - _fields.set(i,field); + set(i,field); put=true; } } } if (!put) - _fields.add(field); + add(field); } /** @@ -410,7 +385,7 @@ public class HttpFields implements Iterable return; HttpField field = new HttpField(name, value); - _fields.add(field); + add(field); } public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException @@ -431,7 +406,7 @@ public class HttpFields implements Iterable if (value == null) throw new IllegalArgumentException("null value"); HttpField field = new HttpField(header, value); - _fields.add(field); + add(field); } /** @@ -441,11 +416,11 @@ public class HttpFields implements Iterable */ public HttpField remove(HttpHeader name) { - for (int i=_fields.size();i-->0;) + for (int i=size();i-->0;) { - HttpField f=_fields.get(i); + HttpField f=get(i); if (f.getHeader()==name) - return _fields.remove(i); + return remove(i); } return null; } @@ -457,11 +432,11 @@ public class HttpFields implements Iterable */ public HttpField remove(String name) { - for (int i=_fields.size();i-->0;) + for (int i=size();i-->0;) { - HttpField f=_fields.get(i); + HttpField f=get(i); if (f.getName().equalsIgnoreCase(name)) - return _fields.remove(i); + return remove(i); } return null; } @@ -570,7 +545,7 @@ public class HttpFields implements Iterable try { StringBuilder buffer = new StringBuilder(); - for (HttpField field : _fields) + for (HttpField field : this) { if (field != null) { @@ -591,21 +566,6 @@ public class HttpFields implements Iterable return e.toString(); } } - - /** - * Clear the header. - */ - public void clear() - { - _fields.clear(); - } - - public void add(HttpField field) - { - _fields.add(field); - } - - /** * Add fields from another HttpFields instance. Single valued fields are replaced, while all diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index f0212102064..3a65caa1218 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -436,4 +436,32 @@ public class HttpFieldsTest assertEquals(""+i,i>=4,header.contains(""+i,"def")); } } + + @Test + public void testValues() + { + String[] values = new HttpField("name","value").getValues(); + assertEquals(1,values.length); + assertEquals("value",values[0]); + + + values = new HttpField("name","a,b,c").getValues(); + assertEquals(3,values.length); + assertEquals("a",values[0]); + assertEquals("b",values[1]); + assertEquals("c",values[2]); + + values = new HttpField("name","a,\"x,y,z\",c").getValues(); + assertEquals(3,values.length); + assertEquals("a",values[0]); + assertEquals("x,y,z",values[1]); + assertEquals("c",values[2]); + + values = new HttpField("name","a,\"x,\\\"p,q\\\",z\",c").getValues(); + assertEquals(3,values.length); + assertEquals("a",values[0]); + assertEquals("x,\"p,q\",z",values[1]); + assertEquals("c",values[2]); + + } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java index 15b6f410691..1006d3a9740 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java @@ -19,14 +19,11 @@ package org.eclipse.jetty.http2.hpack; -import java.util.ArrayList; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; @@ -35,9 +32,9 @@ import org.eclipse.jetty.http.HttpScheme; */ public class MetaData implements Iterable { - private final Iterable _fields; + private final HttpFields _fields; - public MetaData(Iterable fields) + public MetaData(HttpFields fields) { _fields=fields; } @@ -58,14 +55,9 @@ public class MetaData implements Iterable return _fields.iterator(); } - public List getFields() + public HttpFields getFields() { - if (_fields instanceof List) - return (List)_fields; - ArrayList list = new ArrayList<>(); - for (HttpField field:_fields) - list.add(field); - return list; + return _fields; } @Override @@ -112,7 +104,7 @@ public class MetaData implements Iterable private final int _port; private final String _path; - public Request(HttpScheme scheme, String method, String authority, String host, int port, String path, Iterable fields) + public Request(HttpScheme scheme, String method, String authority, String host, int port, String path, HttpFields fields) { super(fields); _authority=authority; @@ -200,12 +192,6 @@ public class MetaData implements Iterable _status=status; } - public Response(int status, Iterable fields) - { - super(fields); - _status=status; - } - @Override public boolean isRequest() { diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 49066b91b50..8c1697d63c9 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -19,12 +19,10 @@ package org.eclipse.jetty.http2.hpack; -import java.util.ArrayList; -import java.util.List; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; /* -------------------------------------------------------- */ @@ -40,7 +38,7 @@ public class MetaDataBuilder private int _port; private String _path; - List _fields = new ArrayList<>(); + HttpFields _fields = new HttpFields(10); public void emit(HttpField field) { @@ -104,11 +102,13 @@ public class MetaDataBuilder { try { + HttpFields fields = _fields; + _fields = new HttpFields(Math.max(10,fields.size()+5)); if (_method!=null) - return new MetaData.Request(_scheme,_method,_authority,_host,_port,_path,new ArrayList<>(_fields)); + return new MetaData.Request(_scheme,_method,_authority,_host,_port,_path,fields); if (_status!=0) - return new MetaData.Response(_status,new ArrayList<>(_fields)); - return new MetaData(new ArrayList<>(_fields)); + return new MetaData.Response(_status,fields); + return new MetaData(fields); } finally { @@ -119,7 +119,6 @@ public class MetaDataBuilder _path=null; _host=null; _port=0; - _fields.clear(); } } } From f258ff1565e2a3d362b2e8c6c9d523dd47ab1996 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 11 Jun 2014 17:05:39 +0200 Subject: [PATCH 058/269] improved debug --- .../src/main/java/org/eclipse/jetty/http2/parser/Parser.java | 2 +- .../main/java/org/eclipse/jetty/http2/hpack/HpackContext.java | 3 +-- .../test/java/org/eclipse/jetty/http2/server/Http2Server.java | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index c5ab2b39415..c1463248bc9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -76,7 +76,7 @@ public class Parser { if (LOG.isDebugEnabled()) { - int l=Math.min(buffer.remaining(),16); + int l=Math.min(buffer.remaining(),32); LOG.debug("Parsing "+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l)+(l Date: Wed, 11 Jun 2014 17:41:52 +0200 Subject: [PATCH 059/269] revert httpfields --- .../org/eclipse/jetty/http/HttpFields.java | 100 ++++++++++++------ .../eclipse/jetty/http2/hpack/MetaData.java | 2 +- .../http2/server/HttpChannelOverHTTP2.java | 5 +- 3 files changed, 71 insertions(+), 36 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index b9031cdb276..98327caea2d 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -48,17 +49,19 @@ import org.eclipse.jetty.util.log.Logger; *

The cookie handling provided by this class is guided by the Servlet specification and RFC6265. * */ -public class HttpFields extends ArrayList +public class HttpFields implements Iterable { - private static final long serialVersionUID = 1L; private static final Logger LOG = Log.getLogger(HttpFields.class); public final static String __separators = ", \t"; + final List _fields; + /** * Constructor. */ public HttpFields() { + _fields=new ArrayList<>(); } /** @@ -66,7 +69,18 @@ public class HttpFields extends ArrayList */ public HttpFields(int capacity) { - super(capacity); + _fields=new ArrayList<>(capacity); + } + + public int size() + { + return _fields.size(); + } + + @Override + public Iterator iterator() + { + return _fields.iterator(); } /** @@ -74,7 +88,7 @@ public class HttpFields extends ArrayList */ public Collection getFieldNamesCollection() { - final Set list = new HashSet<>(size()); + final Set list = new HashSet<>(_fields.size()); for (HttpField f : this) { if (f!=null) @@ -99,14 +113,14 @@ public class HttpFields extends ArrayList */ public HttpField getField(int i) { - return get(i); + return _fields.get(i); } public HttpField getField(HttpHeader header) { - for (int i=0;i public HttpField getField(String name) { - for (int i=0;i0;) + { + if (_fields.get(i).equals(field)) + return true; + } + return false; + } + public boolean contains(HttpHeader header, String value) { - for (int i=0;i0;) { - HttpField f=get(i); + HttpField f=_fields.get(i); if (f.getHeader()==header && f.contains(value)) return true; } @@ -137,9 +161,9 @@ public class HttpFields extends ArrayList public boolean contains(String name, String value) { - for (int i=0;i0;) { - HttpField f=get(i); + HttpField f=_fields.get(i); if (f.getName().equalsIgnoreCase(name) && f.contains(value)) return true; } @@ -149,9 +173,9 @@ public class HttpFields extends ArrayList public boolean containsKey(String name) { - for (int i=0;i0;) { - HttpField f=get(i); + HttpField f=_fields.get(i); if (f.getName().equalsIgnoreCase(name)) return true; } @@ -207,9 +231,9 @@ public class HttpFields extends ArrayList */ public Enumeration getValues(final String name) { - for (int i=0;i { if (field==null) { - while (i public void put(HttpField field) { boolean put=false; - for (int i=size();i-->0;) + for (int i=_fields.size();i-->0;) { - HttpField f=get(i); + HttpField f=_fields.get(i); if (f.isSameName(field)) { if (put) - remove(i); + _fields.remove(i); else { - set(i,field); + _fields.set(i,field); put=true; } } } if (!put) - add(field); + _fields.add(field); } /** @@ -385,7 +409,7 @@ public class HttpFields extends ArrayList return; HttpField field = new HttpField(name, value); - add(field); + _fields.add(field); } public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException @@ -406,7 +430,7 @@ public class HttpFields extends ArrayList if (value == null) throw new IllegalArgumentException("null value"); HttpField field = new HttpField(header, value); - add(field); + _fields.add(field); } /** @@ -416,11 +440,11 @@ public class HttpFields extends ArrayList */ public HttpField remove(HttpHeader name) { - for (int i=size();i-->0;) + for (int i=_fields.size();i-->0;) { - HttpField f=get(i); + HttpField f=_fields.get(i); if (f.getHeader()==name) - return remove(i); + return _fields.remove(i); } return null; } @@ -432,11 +456,11 @@ public class HttpFields extends ArrayList */ public HttpField remove(String name) { - for (int i=size();i-->0;) + for (int i=_fields.size();i-->0;) { - HttpField f=get(i); + HttpField f=_fields.get(i); if (f.getName().equalsIgnoreCase(name)) - return remove(i); + return _fields.remove(i); } return null; } @@ -566,6 +590,16 @@ public class HttpFields extends ArrayList return e.toString(); } } + + public void clear() + { + _fields.clear(); + } + + public void add(HttpField field) + { + _fields.add(field); + } /** * Add fields from another HttpFields instance. Single valued fields are replaced, while all diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java index 1006d3a9740..be41545a11a 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java @@ -67,7 +67,7 @@ public class MetaData implements Iterable return false; MetaData m = (MetaData)o; - List lm=m.getFields(); + HttpFields lm=m.getFields(); int s=0; for (HttpField field: this) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index bd23ace1fd6..9e74e4b6345 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.List; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; @@ -77,10 +78,10 @@ public class HttpChannelOverHTTP2 extends HttpChannel parsedHostHeader(requestMetaData.getHost(), requestMetaData.getPort()); - List fields = requestMetaData.getFields(); + HttpFields fields = requestMetaData.getFields(); for (int i = 0; i < fields.size(); ++i) { - HttpField field = fields.get(i); + HttpField field = fields.getField(i); parsedHeader(field); } From c8e2a79237bcd9bff43faf3c277e6ba01a0f9c0d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 11 Jun 2014 18:07:36 +0200 Subject: [PATCH 060/269] fixed bad test header --- .../java/org/eclipse/jetty/security/DataConstraintsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/DataConstraintsTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/DataConstraintsTest.java index 39d4a189e29..117ea504cb7 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/DataConstraintsTest.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/DataConstraintsTest.java @@ -375,10 +375,10 @@ public class DataConstraintsTest response = _connectorS.getResponses("GET /ctx/restricted/info HTTP/1.0\r\n\r\n"); Assert.assertThat(response, Matchers.containsString("HTTP/1.1 403 Forbidden")); - response = _connector.getResponses("GET /ctx/restricted/info HTTP/1.0\r\n Authorization: Basic YWRtaW46cGFzc3dvcmQ=\r\n\r\n"); + response = _connector.getResponses("GET /ctx/restricted/info HTTP/1.0\r\nAuthorization: Basic YWRtaW46cGFzc3dvcmQ=\r\n\r\n"); Assert.assertThat(response, Matchers.containsString("HTTP/1.1 403 Forbidden")); - response = _connectorS.getResponses("GET /ctx/restricted/info HTTP/1.0\r\n Authorization: Basic YWRtaW46cGFzc3dvcmQ=\r\n\r\n"); + response = _connectorS.getResponses("GET /ctx/restricted/info HTTP/1.0\r\nAuthorization: Basic YWRtaW46cGFzc3dvcmQ=\r\n\r\n"); Assert.assertThat(response, Matchers.containsString("HTTP/1.1 403 Forbidden")); } From 78cbed12363ee1d9f6f66496195e410c316373e1 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 11 Jun 2014 13:36:52 +0200 Subject: [PATCH 061/269] Added headerTableSize parameter. --- .../eclipse/jetty/http2/generator/Generator.java | 4 ++-- .../http2/server/HTTP2ServerConnectionFactory.java | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index dda42dc0065..c326e8da3c5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -29,12 +29,12 @@ public class Generator private final ByteBufferPool byteBufferPool; private final FrameGenerator[] generators; - public Generator(ByteBufferPool byteBufferPool) + public Generator(ByteBufferPool byteBufferPool, int headerTableSize) { this.byteBufferPool = byteBufferPool; HeaderGenerator headerGenerator = new HeaderGenerator(); - HpackEncoder encoder = new HpackEncoder(); + HpackEncoder encoder = new HpackEncoder(headerTableSize); this.generators = new FrameGenerator[FrameType.values().length]; this.generators[FrameType.DATA.getType()] = new DataGenerator(headerGenerator); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 2d2a581dc0f..e844c33ce41 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -43,6 +43,7 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory private static final String CHANNEL_ATTRIBUTE = HttpChannelOverHTTP2.class.getName(); private final HttpConfiguration httpConfiguration; + private int headerTableSize = 4096; public HTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration) { @@ -50,12 +51,22 @@ public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory this.httpConfiguration = httpConfiguration; } + public int getHeaderTableSize() + { + return headerTableSize; + } + + public void setHeaderTableSize(int headerTableSize) + { + this.headerTableSize = headerTableSize; + } + @Override public Connection newConnection(Connector connector, EndPoint endPoint) { Session.Listener listener = new HTTPServerSessionListener(connector, httpConfiguration, endPoint); - Generator generator = new Generator(connector.getByteBufferPool()); + Generator generator = new Generator(connector.getByteBufferPool(), getHeaderTableSize()); HTTP2ServerSession session = new HTTP2ServerSession(endPoint, generator, listener); Parser parser = new ServerParser(connector.getByteBufferPool(), session); From 8e4c6b7fdddb0df81225a794aac7d12f984f413d Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 11 Jun 2014 18:23:51 +0200 Subject: [PATCH 062/269] Put some more flesh on the HTTP2 implementation. --- jetty-http2/http2-client/pom.xml | 78 ++++++ .../jetty/http2/client/HTTP2Client.java | 169 ++++++++++++ .../http2/client/HTTP2ClientSession.java | 77 ++++++ .../eclipse/jetty/http2/client/HTTP2Test.java | 186 ++++++++++++++ .../test/resources/jetty-logging.properties | 2 + .../org/eclipse/jetty/http2/FlowControl.java | 28 ++ .../eclipse/jetty/http2/HTTP2FlowControl.java | 38 +++ .../org/eclipse/jetty/http2/HTTP2Session.java | 242 +++++++++++++++++- .../org/eclipse/jetty/http2/HTTP2Stream.java | 122 +++++++-- .../org/eclipse/jetty/http2/ISession.java | 3 + .../java/org/eclipse/jetty/http2/IStream.java | 17 +- .../org/eclipse/jetty/http2/api/Session.java | 10 +- .../org/eclipse/jetty/http2/api/Stream.java | 12 +- .../jetty/http2/frames/SettingsFrame.java | 5 + .../jetty/http2/generator/Generator.java | 12 + .../eclipse/jetty/http2/parser/Parser.java | 9 +- .../jetty/http2/parser/PrefaceParser.java | 1 + .../server/HTTP2ServerConnectionFactory.java | 21 +- .../http2/server/HTTP2ServerSession.java | 39 ++- .../http2/server/HttpChannelOverHTTP2.java | 10 +- jetty-http2/pom.xml | 1 + 21 files changed, 1021 insertions(+), 61 deletions(-) create mode 100644 jetty-http2/http2-client/pom.xml create mode 100644 jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java create mode 100644 jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java create mode 100644 jetty-http2/http2-client/src/test/resources/jetty-logging.properties create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java diff --git a/jetty-http2/http2-client/pom.xml b/jetty-http2/http2-client/pom.xml new file mode 100644 index 00000000000..42ef50da4ed --- /dev/null +++ b/jetty-http2/http2-client/pom.xml @@ -0,0 +1,78 @@ + + + + org.eclipse.jetty.http2 + http2-parent + 10.0.0-SNAPSHOT + + + 4.0.0 + http2-client + Jetty :: HTTP2 :: Client + + + + + org.apache.felix + maven-bundle-plugin + true + + + + manifest + + + + javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,* + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + + + + org.eclipse.jetty.http2 + http2-common + ${project.version} + + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + org.eclipse.jetty + jetty-server + ${project.version} + test + + + org.eclipse.jetty + jetty-servlet + ${project.version} + test + + + org.eclipse.jetty.http2 + http2-server + ${project.version} + test + + + + diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java new file mode 100644 index 00000000000..626ce7998ff --- /dev/null +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -0,0 +1,169 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; + +import org.eclipse.jetty.http2.HTTP2Connection; +import org.eclipse.jetty.http2.HTTP2FlowControl; +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.ErrorCode; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.http2.parser.PrefaceParser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.eclipse.jetty.io.SelectChannelEndPoint; +import org.eclipse.jetty.io.SelectorManager; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; +import org.eclipse.jetty.util.thread.Scheduler; + +public class HTTP2Client extends ContainerLifeCycle +{ + private final Queue sessions = new ConcurrentLinkedQueue<>(); + private final Executor executor; + private final Scheduler scheduler; + private final SelectorManager selector; + private final ByteBufferPool byteBufferPool; + + public HTTP2Client() + { + this(new QueuedThreadPool()); + } + + public HTTP2Client(Executor executor) + { + this.executor = executor; + addBean(executor); + this.scheduler = new ScheduledExecutorScheduler(); + addBean(scheduler, true); + this.selector = new ClientSelectorManager(executor, scheduler); + addBean(selector, true); + this.byteBufferPool = new MappedByteBufferPool(); + addBean(byteBufferPool, true); + } + + @Override + protected void doStop() throws Exception + { + closeConnections(); + super.doStop(); + } + + public void connect(InetSocketAddress address, Session.Listener listener, Promise promise) + { + try + { + SocketChannel channel = SocketChannel.open(); + channel.socket().setTcpNoDelay(true); + channel.configureBlocking(false); + channel.connect(address); + selector.connect(channel, new Context(listener, promise)); + } + catch (Throwable x) + { + promise.failed(x); + } + } + + private void closeConnections() + { + for (Session session : sessions) + session.close(ErrorCode.NO_ERROR, null, Callback.Adapter.INSTANCE); + sessions.clear(); + } + + private class ClientSelectorManager extends SelectorManager + { + private ClientSelectorManager(Executor executor, Scheduler scheduler) + { + super(executor, scheduler); + } + + @Override + protected EndPoint newEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException + { + return new SelectChannelEndPoint(channel, selector, selectionKey, getScheduler(), 30000); + } + + @Override + public Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException + { + Context context = (Context)attachment; + Generator generator = new Generator(byteBufferPool, 4096); + HTTP2Session session = new HTTP2ClientSession(endpoint, generator, context.listener, new HTTP2FlowControl(), 65535); + Parser parser = new Parser(byteBufferPool, session); + Connection connection = new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, 8192, session); + context.promise.succeeded(session); + return connection; + } + } + + private class HTTP2ClientConnection extends HTTP2Connection + { + private final Session session; + + public HTTP2ClientConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, int bufferSize, Session session) + { + super(byteBufferPool, executor, endpoint, parser, bufferSize); + this.session = session; + } + + @Override + public void onOpen() + { + super.onOpen(); + sessions.offer(session); + getEndPoint().write(Callback.Adapter.INSTANCE, ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES)); + } + + @Override + public void onClose() + { + super.onClose(); + sessions.remove(session); + } + } + + private class Context + { + private final Session.Listener listener; + private final Promise promise; + + private Context(Session.Listener listener, Promise promise) + { + this.listener = listener; + this.promise = promise; + } + } +} diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java new file mode 100644 index 00000000000..a4a00885100 --- /dev/null +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -0,0 +1,77 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import org.eclipse.jetty.http2.FlowControl; +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.IStream; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.ErrorCode; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class HTTP2ClientSession extends HTTP2Session +{ + private static final Logger LOG = Log.getLogger(HTTP2ClientSession.class); + + public HTTP2ClientSession(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int initialWindowSize) + { + super(endPoint, generator, listener, flowControl, initialWindowSize, 1); + } + + @Override + public boolean onHeaders(HeadersFrame frame) + { + int streamId = frame.getStreamId(); + IStream stream = getStream(streamId); + if (stream == null) + { + ResetFrame reset = new ResetFrame(streamId, ErrorCode.STREAM_CLOSED_ERROR); + reset(reset, disconnectCallback); + } + else + { + stream.updateClose(frame.isEndStream(), false); + stream.process(frame); + notifyHeaders(stream, frame); + if (stream.isClosed()) + removeStream(stream, false); + } + return false; + } + + private void notifyHeaders(IStream stream, HeadersFrame frame) + { + Stream.Listener listener = stream.getListener(); + if (listener == null) + return; + try + { + listener.onHeaders(stream, frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } +} diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java new file mode 100644 index 00000000000..3af73779ed0 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -0,0 +1,186 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +public class HTTP2Test +{ + private Server server; + private ServerConnector connector; + private String path; + private HTTP2Client client; + + private void startServer(HttpServlet servlet) throws Exception + { + QueuedThreadPool serverExecutor = new QueuedThreadPool(); + serverExecutor.setName("server"); + server = new Server(serverExecutor); + connector = new ServerConnector(server, new HTTP2ServerConnectionFactory(new HttpConfiguration())); + server.addConnector(connector); + + ServletContextHandler context = new ServletContextHandler(server, "/"); + path = "/test"; + context.addServlet(new ServletHolder(servlet), path); + + QueuedThreadPool clientExecutor = new QueuedThreadPool(); + clientExecutor.setName("client"); + client = new HTTP2Client(clientExecutor); + server.addBean(client); + + server.start(); + } + + @After + public void dispose() throws Exception + { + server.stop(); + } + + @Test + public void testRequestNoContentResponseNoContent() throws Exception + { + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + } + }); + + String host = "localhost"; + int port = connector.getLocalPort(); + String authority = host + ":" + port; + InetSocketAddress address = new InetSocketAddress(host, port); + FuturePromise promise = new FuturePromise<>(); + client.connect(address, new Session.Listener.Adapter(), promise); + Session session = promise.get(); + + HttpFields fields = new HttpFields(); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", authority, host, port, path, fields); + HeadersFrame frame = new HeadersFrame(1, metaData, null, true); + final CountDownLatch latch = new CountDownLatch(1); + session.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + Assert.assertTrue(stream.isClosed()); + Assert.assertTrue(stream.getId() > 0); + + Assert.assertTrue(frame.isEndStream()); + Assert.assertEquals(stream.getId(), frame.getStreamId()); + Assert.assertTrue(frame.getMetaData().isResponse()); + MetaData.Response response = (MetaData.Response)frame.getMetaData(); + Assert.assertEquals(200, response.getStatus()); + + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testRequestNoContentResponseContent() throws Exception + { + final byte[] content = "Hello World!".getBytes(StandardCharsets.UTF_8); + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + resp.getOutputStream().write(content); + } + }); + + String host = "localhost"; + int port = connector.getLocalPort(); + String authority = host + ":" + port; + InetSocketAddress address = new InetSocketAddress(host, port); + FuturePromise promise = new FuturePromise<>(); + client.connect(address, new Session.Listener.Adapter(), promise); + Session session = promise.get(); + + HttpFields fields = new HttpFields(); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", authority, host, port, path, fields); + HeadersFrame frame = new HeadersFrame(1, metaData, null, true); + final CountDownLatch latch = new CountDownLatch(2); + session.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + Assert.assertFalse(stream.isClosed()); + Assert.assertTrue(stream.getId() > 0); + + Assert.assertFalse(frame.isEndStream()); + Assert.assertEquals(stream.getId(), frame.getStreamId()); + Assert.assertTrue(frame.getMetaData().isResponse()); + MetaData.Response response = (MetaData.Response)frame.getMetaData(); + Assert.assertEquals(200, response.getStatus()); + + latch.countDown(); + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + Assert.assertTrue(stream.isClosed()); + + Assert.assertTrue(frame.isEndStream()); + Assert.assertEquals(ByteBuffer.wrap(content), frame.getData()); + + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } +} diff --git a/jetty-http2/http2-client/src/test/resources/jetty-logging.properties b/jetty-http2/http2-client/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..13ddd0bba9d --- /dev/null +++ b/jetty-http2/http2-client/src/test/resources/jetty-logging.properties @@ -0,0 +1,2 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.http2.LEVEL=DEBUG diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java new file mode 100644 index 00000000000..c5b029ac9b6 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java @@ -0,0 +1,28 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +public interface FlowControl +{ + public void onNewStream(IStream stream); + + public int getWindowSize(ISession session); + + public void setWindowSize(ISession session, int windowSize); +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java new file mode 100644 index 00000000000..7845025038e --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -0,0 +1,38 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +public class HTTP2FlowControl implements FlowControl +{ + @Override + public void onNewStream(IStream stream) + { + } + + @Override + public int getWindowSize(ISession session) + { + return 0; + } + + @Override + public void setWindowSize(ISession session, int windowSize) + { + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 6ffa9e8df41..87c27f80b79 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -19,10 +19,16 @@ package org.eclipse.jetty.http2; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; +import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; @@ -34,9 +40,11 @@ import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.ArrayQueue; +import org.eclipse.jetty.util.Atomics; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.Promise; @@ -47,24 +55,74 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { private static final Logger LOG = Log.getLogger(HTTP2Session.class); + protected final Callback disconnectCallback = new Callback.Adapter() + { + @Override + public void failed(Throwable x) + { + disconnect(); + } + }; + private final ConcurrentMap streams = new ConcurrentHashMap<>(); + private final AtomicInteger streamIds = new AtomicInteger(); + private final AtomicInteger lastStreamId = new AtomicInteger(); + private final AtomicInteger streamCount = new AtomicInteger(); private final Flusher flusher = new Flusher(); private final EndPoint endPoint; private final Generator generator; private final Listener listener; + private final FlowControl flowControl; + private final int initialWindowSize; + private volatile int maxStreamCount; - public HTTP2Session(EndPoint endPoint, Generator generator, Listener listener) + public HTTP2Session(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int initialWindowSize, int initialStreamId) { this.endPoint = endPoint; this.generator = generator; this.listener = listener; + this.flowControl = flowControl; + this.initialWindowSize = initialWindowSize; + this.maxStreamCount = -1; + this.streamIds.set(initialStreamId); + } + + public Generator getGenerator() + { + return generator; + } + + public int getInitialWindowSize() + { + return initialWindowSize; + } + + public int getMaxStreamCount() + { + return maxStreamCount; + } + + public FlowControl getFlowControl() + { + return flowControl; } @Override public boolean onData(DataFrame frame) { - IStream stream = streams.get(frame.getStreamId()); - return stream.process(frame); + int streamId = frame.getStreamId(); + IStream stream = getStream(streamId); + if (stream != null) + { + stream.updateClose(frame.isEndStream(), false); + return stream.process(frame); + } + else + { + ResetFrame resetFrame = new ResetFrame(streamId, ErrorCode.STREAM_CLOSED_ERROR); + reset(resetFrame, disconnectCallback); + return false; + } } @Override @@ -85,6 +143,20 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onSettings(SettingsFrame frame) { + Map settings = frame.getSettings(); + if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) + { + maxStreamCount = settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS); + LOG.debug("Updated max concurrent streams to {}", maxStreamCount); + } + if (settings.containsKey(SettingsFrame.INITIAL_WINDOW_SIZE)) + { + int windowSize = settings.get(SettingsFrame.INITIAL_WINDOW_SIZE); + setWindowSize(windowSize); + LOG.debug("Updated window size to {}", windowSize); + } + // TODO: handle other settings + notifySettings(this, frame); return false; } @@ -113,9 +185,29 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } @Override - public void newStream(HeadersFrame frame, Stream.Listener listener, Promise promise) + public void newStream(HeadersFrame frame, final Promise promise, Stream.Listener listener) { - + // Synchronization is necessary to atomically create + // the stream id and enqueue the frame to be sent. + synchronized (this) + { + int streamId = streamIds.getAndAdd(2); + PriorityFrame priority = frame.getPriority(); + priority = priority == null ? null : new PriorityFrame(streamId, priority.getDependentStreamId(), + priority.getWeight(), priority.isExclusive()); + frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream()); + final IStream stream = createLocalStream(frame); + if (stream == null) + { + promise.failed(new IllegalStateException()); + return; + } + stream.updateClose(frame.isEndStream(), true); + stream.setListener(listener); + flusher.offer(generator.generate(frame, new PromiseCallback<>(promise, stream))); + } + // Iterate outside the synchronized block. + flusher.iterate(); } @Override @@ -137,9 +229,11 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } @Override - public void close(GoAwayFrame frame, Callback callback) + public void close(int error, String reason, Callback callback) { - + byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); + GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); + frame(frame, callback); } @Override @@ -154,9 +248,96 @@ public abstract class HTTP2Session implements ISession, Parser.Listener endPoint.close(); } - protected IStream putIfAbsent(IStream stream) + protected IStream createLocalStream(HeadersFrame frame) { - return streams.putIfAbsent(stream.getId(), stream); + IStream stream = newStream(frame); + int streamId = stream.getId(); + updateLastStreamId(streamId); + if (streams.putIfAbsent(streamId, stream) == null) + { + LOG.debug("Created local {}", stream); + return stream; + } + else + { + return null; + } + } + + protected IStream createRemoteStream(HeadersFrame frame) + { + int streamId = frame.getStreamId(); + + // SPEC: exceeding max concurrent streams is treated as stream error. + while (true) + { + int currentStreams = streamCount.get(); + int maxStreams = maxStreamCount; + if (maxStreams >= 0 && currentStreams >= maxStreams) + { + reset(new ResetFrame(streamId, ErrorCode.PROTOCOL_ERROR), disconnectCallback); + return null; + } + if (streamCount.compareAndSet(currentStreams, currentStreams + 1)) + break; + } + + IStream stream = newStream(frame); + + // SPEC: duplicate stream is treated as connection error. + if (streams.putIfAbsent(streamId, stream) == null) + { + updateLastStreamId(streamId); + LOG.debug("Created remote {}", stream); + return stream; + } + else + { + close(ErrorCode.PROTOCOL_ERROR, "duplicate_stream", disconnectCallback); + return null; + } + } + + protected IStream newStream(HeadersFrame frame) + { + return new HTTP2Stream(this, frame); + } + + protected void removeStream(IStream stream, boolean local) + { + IStream removed = streams.remove(stream.getId()); + if (removed != null) + { + assert removed == stream; + + if (local) + streamCount.decrementAndGet(); + + LOG.debug("Removed {}", stream); + } + } + + @Override + public Collection getStreams() + { + List result = new ArrayList<>(); + result.addAll(streams.values()); + return result; + } + + public IStream getStream(int streamId) + { + return streams.get(streamId); + } + + private void updateLastStreamId(int streamId) + { + Atomics.updateMax(lastStreamId, streamId); + } + + public void setWindowSize(int initialWindowSize) + { + flowControl.setWindowSize(this, initialWindowSize); } protected Stream.Listener notifyNewStream(Stream stream, HeadersFrame frame) @@ -172,17 +353,34 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } + protected void notifySettings(Session session, SettingsFrame frame) + { + try + { + listener.onSettings(session, frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } + private class Flusher extends IteratingCallback { private final ArrayQueue queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH); private Generator.LeaseCallback active; - private void flush(Generator.LeaseCallback lease) + private void offer(Generator.LeaseCallback lease) { synchronized (queue) { queue.offer(lease); } + } + + private void flush(Generator.LeaseCallback lease) + { + offer(lease); iterate(); } @@ -222,4 +420,28 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { } } + + public class PromiseCallback implements Callback + { + private final Promise promise; + private final C value; + + public PromiseCallback(Promise promise, C value) + { + this.promise = promise; + this.value = value; + } + + @Override + public void succeeded() + { + promise.succeeded(value); + } + + @Override + public void failed(Throwable x) + { + promise.failed(x); + } + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 51463d911f3..122eaea4623 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -23,12 +23,18 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class HTTP2Stream implements IStream { + private static final Logger LOG = Log.getLogger(HTTP2Stream.class); + private final AtomicReference> attributes = new AtomicReference<>(); + private final AtomicReference closeState = new AtomicReference<>(CloseState.NOT_CLOSED); private final ISession session; private final HeadersFrame frame; private Listener listener; @@ -81,6 +87,12 @@ public class HTTP2Stream implements IStream return attributes().remove(key); } + @Override + public boolean isClosed() + { + return closeState.get() == CloseState.CLOSED; + } + private ConcurrentMap attributes() { ConcurrentMap map = attributes.get(); @@ -96,35 +108,108 @@ public class HTTP2Stream implements IStream } @Override - public void setListener(Listener listener) + public Listener getListener() { - + return listener; } @Override - public boolean process(DataFrame frame) + public void setListener(Listener listener) { - return notifyData(frame); + this.listener = listener; + } + + @Override + public boolean process(Frame frame) + { + switch (frame.getType()) + { + case DATA: + { + return notifyData((DataFrame)frame); + } + case HEADERS: + { + return false; + } + default: + throw new UnsupportedOperationException(); + } + } + + @Override + public void updateClose(boolean update, boolean local) + { + if (LOG.isDebugEnabled()) + LOG.debug("Update close for {} close={} local={}", this, update, local); + + if (!update) + return; + + while (true) + { + CloseState current = closeState.get(); + switch (current) + { + case NOT_CLOSED: + { + CloseState newValue = local ? CloseState.LOCALLY_CLOSED : CloseState.REMOTELY_CLOSED; + if (closeState.compareAndSet(current, newValue)) + return; + break; + } + case LOCALLY_CLOSED: + { + if (local) + return; + if (closeState.compareAndSet(current, CloseState.CLOSED)) + return; + break; + } + case REMOTELY_CLOSED: + { + if (!local) + return; + if (closeState.compareAndSet(current, CloseState.CLOSED)) + return; + break; + } + default: + { + return; + } + } + } } protected boolean notifyData(DataFrame frame) { final Listener listener = this.listener; - listener.onData(this, frame, new Callback() + if (listener == null) + return false; + try { - @Override - public void succeeded() + listener.onData(this, frame, new Callback() { - // TODO: notify flow control - } + @Override + public void succeeded() + { + // TODO: notify flow control + } - @Override - public void failed(Throwable x) - { - // TODO: bail out - } - }); - return true; + @Override + public void failed(Throwable x) + { + // TODO: bail out + } + }); + return false; + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } } @Override @@ -132,4 +217,9 @@ public class HTTP2Stream implements IStream { return String.format("%s@%x", getClass().getSimpleName(), hashCode()); } + + private enum CloseState + { + NOT_CLOSED, LOCALLY_CLOSED, REMOTELY_CLOSED, CLOSED + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index 905ccb30bd8..e3c4a11c9b0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -24,5 +24,8 @@ import org.eclipse.jetty.util.Callback; public interface ISession extends Session { + @Override + IStream getStream(int streamId); + public void frame(Frame frame, Callback callback); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 47f7c802c2e..d7cc0222965 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -19,14 +19,27 @@ package org.eclipse.jetty.http2; import org.eclipse.jetty.http2.api.Stream; -import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.Frame; public interface IStream extends Stream { @Override public ISession getSession(); + public Listener getListener(); + public void setListener(Listener listener); - public boolean process(DataFrame frame); + public boolean process(Frame frame); + + /** + * Updates the close state of this stream. + * + * @param update whether to update the close state + * @param local whether the update comes from a local operation + * (such as sending a frame that ends the stream) + * or a remote operation (such as receiving a frame + * that ends the stream). + */ + public void updateClose(boolean update, boolean local); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java index 9d706e3aceb..be83b0caf06 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.http2.api; +import java.util.Collection; + import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; @@ -28,7 +30,7 @@ import org.eclipse.jetty.util.Promise; public interface Session { - public void newStream(HeadersFrame frame, Stream.Listener listener, Promise promise); + public void newStream(HeadersFrame frame, Promise promise, Stream.Listener listener); public void settings(SettingsFrame frame, Callback callback); @@ -36,7 +38,11 @@ public interface Session public void reset(ResetFrame frame, Callback callback); - public void close(GoAwayFrame frame, Callback callback); + public void close(int error, String payload, Callback callback); + + public Collection getStreams(); + + public Stream getStream(int streamId); // TODO: getStreams(), remote and local address, etc. see SPDY's Session diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index 78d696c6ea2..9afc09570b7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -38,28 +38,36 @@ public interface Stream public Object removeAttribute(String key); + public boolean isClosed(); + // TODO: see SPDY's Stream public interface Listener { + public void onHeaders(Stream stream, HeadersFrame frame); + public void onData(Stream stream, DataFrame frame, Callback callback); + // TODO: is this method needed ? public void onFailure(Stream stream, Throwable x); // TODO: See SPDY's StreamFrameListener public static class Adapter implements Listener { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + } + @Override public void onData(Stream stream, DataFrame frame, Callback callback) { - } @Override public void onFailure(Stream stream, Throwable x) { - } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java index 38cf1278771..555865fcc64 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -22,6 +22,11 @@ import java.util.Map; public class SettingsFrame extends Frame { + public static final int HEADER_TABLE_SIZE = 1; + public static final int ENABLE_PUSH = 2; + public static final int MAX_CONCURRENT_STREAMS = 3; + public static final int INITIAL_WINDOW_SIZE = 4; + private final Map settings; private final boolean reply; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index c326e8da3c5..ab5c6396bfe 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -27,11 +27,18 @@ import org.eclipse.jetty.util.Callback; public class Generator { private final ByteBufferPool byteBufferPool; + private final int headerTableSize; private final FrameGenerator[] generators; + public Generator(ByteBufferPool byteBufferPool) + { + this(byteBufferPool, 4096); + } + public Generator(ByteBufferPool byteBufferPool, int headerTableSize) { this.byteBufferPool = byteBufferPool; + this.headerTableSize = headerTableSize; HeaderGenerator headerGenerator = new HeaderGenerator(); HpackEncoder encoder = new HpackEncoder(headerTableSize); @@ -52,6 +59,11 @@ public class Generator } + public int getHeaderTableSize() + { + return headerTableSize; + } + public LeaseCallback generate(Frame frame, Callback callback) { LeaseCallback lease = new LeaseCallback(byteBufferPool, callback); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index c1463248bc9..d74f797e00c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -31,7 +31,6 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.hpack.HpackDecoder; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -74,11 +73,7 @@ public class Parser public boolean parse(ByteBuffer buffer) { - if (LOG.isDebugEnabled()) - { - int l=Math.min(buffer.remaining(),32); - LOG.debug("Parsing "+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l)+(l(), false), new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - // If cannot write the SETTINGS frame, hard disconnect. - disconnect(); - } - }); + // SPEC: send a SETTINGS frame upon receiving the preface. + HashMap settings = new HashMap<>(); + settings.put(SettingsFrame.HEADER_TABLE_SIZE, getGenerator().getHeaderTableSize()); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialWindowSize()); + int maxConcurrentStreams = getMaxStreamCount(); + if (maxConcurrentStreams >= 0) + settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams); + SettingsFrame frame = new SettingsFrame(settings, false); + settings(frame, disconnectCallback); return false; } @Override public boolean onHeaders(HeadersFrame frame) { - // TODO: handle max concurrent streams - // TODO: handle duplicate streams - // TODO: handle empty headers - - IStream stream = new HTTP2Stream(this, frame); - IStream existing = putIfAbsent(stream); - if (existing == null) + IStream stream = createRemoteStream(frame); + if (stream != null) { + stream.updateClose(frame.isEndStream(), false); + stream.process(frame); Stream.Listener listener = notifyNewStream(stream, frame); stream.setListener(listener); + // The listener may have sent a frame that closed the stream. + if (stream.isClosed()) + removeStream(stream, false); } return false; } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 9e74e4b6345..9b912c19a44 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -19,10 +19,10 @@ package org.eclipse.jetty.http2.server; import java.nio.ByteBuffer; -import java.util.List; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; @@ -78,12 +78,20 @@ public class HttpChannelOverHTTP2 extends HttpChannel parsedHostHeader(requestMetaData.getHost(), requestMetaData.getPort()); + // The specification says user agents MUST support gzip encoding. + // Based on that, some browser does not send the header, but it's + // important that applications can find it (e.g. GzipFilter). + boolean hasAcceptEncodingGzip = false; HttpFields fields = requestMetaData.getFields(); for (int i = 0; i < fields.size(); ++i) { HttpField field = fields.getField(i); + if (HttpHeader.ACCEPT_ENCODING.is(field.getName())) + hasAcceptEncodingGzip = field.getValue().contains("gzip"); parsedHeader(field); } + if (!hasAcceptEncodingGzip) + parsedHeader(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip")); headerComplete(); diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index 7aadaaaa321..6ced51c6dfd 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -15,6 +15,7 @@ http2-hpack http2-common + http2-client http2-server From 330d8f9ea99467d78922dd36d474db4e074282cd Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 11 Jun 2014 18:32:43 +0200 Subject: [PATCH 063/269] Added JDK 7u60 files for NPN and ALPN. --- .../config/modules/protonego-impl/alpn-1.7.0_60.mod | 8 ++++++++ .../config/modules/protonego-impl/npn-1.7.0_60.mod | 8 ++++++++ .../usecases/home/modules/npn/npn-1.7.0_60.mod | 8 ++++++++ pom.xml | 13 +++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod create mode 100644 jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_60.mod diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod new file mode 100644 index 00000000000..45bbad75c9f --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod new file mode 100644 index 00000000000..639c70e3ffd --- /dev/null +++ b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar + +[exec] +-Xbootclasspath/p:lib/npn/npn-boot-1.1.7.v20140316.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_60.mod b/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_60.mod new file mode 100644 index 00000000000..6f6b4250803 --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_60.mod @@ -0,0 +1,8 @@ +[name] +npn-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar + +[exec] +-Xbootclasspath/p:lib/npn/npn-boot-1.1.7.v20140316.jar diff --git a/pom.xml b/pom.xml index 4b732b4682f..3481c34ad18 100644 --- a/pom.xml +++ b/pom.xml @@ -878,6 +878,19 @@ 7.0.0.v20140317 + + 7u60 + + + java.version + 1.7.0_60 + + + + 1.1.7.v20140316 + 7.0.0.v20140317 + + 8u00 From 5a7f954262236b2533f839bc558434b0f3c5f0e5 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 11 Jun 2014 21:21:49 +0200 Subject: [PATCH 064/269] Fixed generation of frames via Session API methods. --- .../main/java/org/eclipse/jetty/http2/HTTP2Session.java | 8 ++++---- .../main/java/org/eclipse/jetty/http2/api/Session.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 87c27f80b79..fd986199ae1 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -181,7 +181,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void onConnectionFailure(int error, String reason) { - + // TODO } @Override @@ -213,19 +213,19 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void settings(SettingsFrame frame, Callback callback) { - + frame(frame, callback); } @Override public void ping(PingFrame frame, Callback callback) { - + frame(frame, callback); } @Override public void reset(ResetFrame frame, Callback callback) { - + frame(frame, callback); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java index be83b0caf06..d6a2697b554 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java @@ -44,7 +44,7 @@ public interface Session public Stream getStream(int streamId); - // TODO: getStreams(), remote and local address, etc. see SPDY's Session + // TODO: remote and local address, etc. see SPDY's Session public interface Listener { From 22c42151bd5729a02608a83c2d02b88410b99173 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 11 Jun 2014 22:43:08 +0200 Subject: [PATCH 065/269] Implemented logic to handle a GO_AWAY frame. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 75 +++++++++++++++++-- .../http2/generator/GoAwayGenerator.java | 2 +- .../jetty/http2/parser/BodyParser.java | 1 - .../jetty/http2/parser/PrefaceParser.java | 4 +- .../jetty/http2/server/HTTP2ServerTest.java | 41 ++++++++++ 5 files changed, 111 insertions(+), 12 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index fd986199ae1..d3856e8c095 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -19,11 +19,14 @@ package org.eclipse.jetty.http2; import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; import java.nio.charset.StandardCharsets; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; @@ -45,6 +48,7 @@ import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.Atomics; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.Promise; @@ -169,9 +173,32 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onGoAway(GoAwayFrame frame) { + if (LOG.isDebugEnabled()) + { + String reason = tryConvertPayload(frame.getPayload()); + LOG.debug("Received {}: {}/{}", frame.getType(), frame.getError(), reason); + } + + flusher.close(); + disconnect(); return false; } + private String tryConvertPayload(byte[] payload) + { + if (payload == null) + return ""; + ByteBuffer buffer = BufferUtil.toBuffer(payload); + try + { + return BufferUtil.toUTF8String(buffer); + } + catch (Throwable x) + { + return BufferUtil.toDetailString(buffer); + } + } + @Override public boolean onWindowUpdate(WindowUpdateFrame frame) { @@ -181,7 +208,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void onConnectionFailure(int error, String reason) { - // TODO + close(error, reason, disconnectCallback); } @Override @@ -233,6 +260,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); + LOG.debug("Sending {}: {}", frame.getType(), reason); frame(frame, callback); } @@ -245,6 +273,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener protected void disconnect() { + LOG.debug("Disconnecting"); endPoint.close(); } @@ -367,15 +396,22 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private class Flusher extends IteratingCallback { - private final ArrayQueue queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH); + private final Queue queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH); private Generator.LeaseCallback active; + private boolean closed; private void offer(Generator.LeaseCallback lease) { + boolean fail = false; synchronized (queue) { - queue.offer(lease); + if (closed) + fail = true; + else + queue.offer(lease); } + if (fail) + fail(lease); } private void flush(Generator.LeaseCallback lease) @@ -387,16 +423,16 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override protected Action process() throws Exception { + Generator.LeaseCallback current = null; synchronized (queue) { - active = queue.poll(); + if (!closed) + current = active = queue.poll(); } - if (active == null) - { + if (current == null) return Action.IDLE; - } - List byteBuffers = active.getByteBuffers(); + List byteBuffers = current.getByteBuffers(); endPoint.write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()])); return Action.SCHEDULED; } @@ -419,6 +455,29 @@ public abstract class HTTP2Session implements ISession, Parser.Listener protected void completed() { } + + public void close() + { + Queue queued; + synchronized (queue) + { + closed = true; + queued = new ArrayDeque<>(queue); + } + + while (true) + { + Generator.LeaseCallback item = queued.poll(); + if (item == null) + break; + fail(item); + } + } + + protected void fail(Generator.LeaseCallback item) + { + item.failed(new ClosedChannelException()); + } } public class PromiseCallback implements Callback diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index 6bb93d3336a..0339c4904d2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -39,7 +39,7 @@ public class GoAwayGenerator extends FrameGenerator public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) { GoAwayFrame goAwayFrame = (GoAwayFrame)frame; - generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), null); + generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload()); } public void generateGoAway(ByteBufferPool.Lease lease, int lastStreamId, int error, byte[] payload) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index acdb8e870c7..51fcfda05b9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -165,7 +165,6 @@ public abstract class BodyParser { try { - LOG.debug("goaway: error="+frame.getError()); return listener.onGoAway(frame); } catch (Throwable x) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java index 4d9dc2212c7..d5b6ee55164 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java @@ -25,15 +25,15 @@ import org.eclipse.jetty.util.log.Logger; public class PrefaceParser { - private static final Logger LOG = Log.getLogger(PrefaceParser.class); public static final byte[] PREFACE_BYTES = new byte[] { 0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a }; - private final Parser.Listener listener; + private static final Logger LOG = Log.getLogger(PrefaceParser.class); + private final Parser.Listener listener; private int cursor; public PrefaceParser(Parser.Listener listener) diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 3d33542a889..2a6940edb01 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -38,6 +38,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; @@ -93,6 +94,46 @@ public class HTTP2ServerTest server.stop(); } + @Test + public void testNoPrefaceBytes() throws Exception + { + startServer(new HttpServlet(){}); + + String host = "localhost"; + int port = connector.getLocalPort(); + HttpFields fields = new HttpFields(); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), + host + ":" + port, host, port, path, fields); + HeadersFrame request = new HeadersFrame(1, metaData, null, true); + Generator.LeaseCallback lease = generator.generate(request, Callback.Adapter.INSTANCE); + + // No preface bytes + + try (Socket client = new Socket(host, port)) + { + OutputStream output = client.getOutputStream(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + output.write(BufferUtil.toArray(buffer)); + } + + final CountDownLatch latch = new CountDownLatch(1); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onGoAway(GoAwayFrame frame) + { + latch.countDown(); + return false; + } + }); + + parseResponse(client, parser); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + } + @Test public void testRequestResponseNoContent() throws Exception { From 116d654426c4cdf0da51bb3a537c2d4e99529a31 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 12 Jun 2014 15:08:46 +0200 Subject: [PATCH 066/269] cleaned up debug --- .../org/eclipse/jetty/http2/hpack/AuthorityHttpField.java | 6 ++++++ .../java/org/eclipse/jetty/http2/hpack/HpackEncoder.java | 8 ++++---- .../eclipse/jetty/http2/hpack/StaticValueHttpField.java | 6 ++++++ .../org/eclipse/jetty/http2/hpack/HpackContextTest.java | 2 ++ .../java/org/eclipse/jetty/http2/server/Http2Server.java | 7 ++++++- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java index 121788b66cb..99bdf14593d 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java @@ -35,4 +35,10 @@ public class AuthorityHttpField extends HostPortHttpField { super(null,AUTHORITY,authority); } + + @Override + public String toString() + { + return String.format("%s(preparsed h=%s p=%d)",super.toString(),getHost(),getPort()); + } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 42e912d6181..5345050f6ad 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -287,10 +287,10 @@ public class HpackEncoder if (p>=0) { - encoding="Literal"+ - ((name_entry==null)?"IdxName":"HuffName")+ - (huffman?"HuffName":"LitName")+ - (reference?"Idx":(never_index?"NeverIdx":"")); + encoding="Lit"+ + ((name_entry==null)?"HuffName":"IdxName")+ + (huffman?"HuffVal":"LitVal")+ + (reference?"Idxd":(never_index?"NeverIdx":"")); } if (name_entry!=null) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java index b26345626c3..7be683aa78d 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java @@ -47,4 +47,10 @@ public class StaticValueHttpField extends HttpField { return _value; } + + @Override + public String toString() + { + return super.toString()+"(evaluated)"; + } } \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java index 8c9a978a2ad..46a5cdc7803 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java @@ -695,6 +695,8 @@ public class HpackContextTest HpackContext ctx = new HpackContext(4096); assertEquals("content-length",ctx.get("content-length").getHttpField().getName()); assertEquals("content-length",ctx.get("Content-Length").getHttpField().getName()); + assertTrue(ctx.get("Content-Length").isStatic()); + assertTrue(ctx.get("Content-Type").isStatic()); ctx.add(new HttpField("Wibble","Wobble")); assertEquals("Wibble",ctx.get("wibble").getHttpField().getName()); diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java index 1a3c6ddded0..83019da8c87 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java @@ -27,6 +27,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.hpack.HpackContext; @@ -57,7 +58,7 @@ public class Http2Server { Server server = new Server(); - ServletContextHandler context = new ServletContextHandler(server, "/"); + ServletContextHandler context = new ServletContextHandler(server, "/",ServletContextHandler.SESSIONS); context.setResourceBase("/tmp"); context.addServlet(new ServletHolder(servlet), "/test/*"); context.addServlet(DefaultServlet.class, "/"); @@ -68,6 +69,8 @@ public class Http2Server HttpConfiguration http_config = new HttpConfiguration(); http_config.setSecureScheme("https"); http_config.setSecurePort(8443); + http_config.setSendXPoweredBy(true); + http_config.setSendServerVersion(true); // HTTP connector ServerConnector http = new ServerConnector(server,new HttpConnectionFactory(http_config)); @@ -118,10 +121,12 @@ public class Http2Server @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + HttpSession session = request.getSession(true); response.setHeader("custom","value"); response.setContentType("text/plain"); String content = "Hello from Jetty HTTP2\n"; content+="uri="+request.getRequestURI()+"\n"; + content+="session="+session.getId()+(session.isNew()?"(New)\n":"\n"); content+="date="+new Date()+"\n"; response.setContentLength(content.length()); response.getOutputStream().print(content); From 74bf0000c5b8c18d77fb8fcaa751bad0288b09d2 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 12 Jun 2014 13:51:35 +0200 Subject: [PATCH 067/269] Removed Lease.merge() and cleared lists in recycle(). --- .../main/java/org/eclipse/jetty/io/ByteBufferPool.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index cce31a0cd52..eca6b39af77 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -90,14 +90,6 @@ public interface ByteBufferPool return buffers; } - public Lease merge(Lease that) - { - assert byteBufferPool == that.byteBufferPool; - buffers.addAll(that.buffers); - recycles.addAll(that.recycles); - return this; - } - public long getTotalLength() { long length = 0; @@ -114,6 +106,8 @@ public interface ByteBufferPool if (recycles.get(i)) byteBufferPool.release(buffer); } + buffers.clear(); + recycles.clear(); } } } From 5ed4f312cd6469e35b93d2aab5a225b87b9c724a Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 12 Jun 2014 13:51:46 +0200 Subject: [PATCH 068/269] Implemented flow control. --- .../jetty/http2/client/HTTP2Client.java | 7 +- .../http2/client/HTTP2ClientSession.java | 7 +- .../jetty/http2/client/AbstractTest.java | 106 ++++ .../jetty/http2/client/EmptyHttpServlet.java | 33 ++ .../jetty/http2/client/FlowControlTest.java | 495 ++++++++++++++++++ .../eclipse/jetty/http2/client/HTTP2Test.java | 77 +-- .../org/eclipse/jetty/http2/FlowControl.java | 14 +- .../eclipse/jetty/http2/HTTP2FlowControl.java | 69 ++- .../org/eclipse/jetty/http2/HTTP2Session.java | 295 +++++++++-- .../org/eclipse/jetty/http2/HTTP2Stream.java | 58 +- .../org/eclipse/jetty/http2/ISession.java | 4 +- .../java/org/eclipse/jetty/http2/IStream.java | 7 +- .../org/eclipse/jetty/http2/api/Stream.java | 3 + .../eclipse/jetty/http2/frames/DataFrame.java | 21 +- .../org/eclipse/jetty/http2/frames/Frame.java | 7 +- .../jetty/http2/generator/DataGenerator.java | 3 +- .../jetty/http2/generator/FrameGenerator.java | 3 +- .../jetty/http2/generator/Generator.java | 37 +- .../http2/generator/GoAwayGenerator.java | 3 +- .../http2/generator/HeadersGenerator.java | 3 +- .../jetty/http2/generator/PingGenerator.java | 3 +- .../http2/generator/PriorityGenerator.java | 3 +- .../jetty/http2/generator/ResetGenerator.java | 3 +- .../http2/generator/SettingsGenerator.java | 3 +- .../generator/WindowUpdateGenerator.java | 24 +- .../jetty/http2/parser/DataBodyParser.java | 10 +- .../AbstractHTTP2ServerConnectionFactory.java | 79 +++ .../server/HTTP2ServerConnectionFactory.java | 46 +- .../http2/server/HTTP2ServerSession.java | 9 +- .../RawHTTP2ServerConnectionFactory.java | 39 ++ .../jetty/http2/server/HTTP2ServerTest.java | 10 +- 31 files changed, 1222 insertions(+), 259 deletions(-) create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java create mode 100644 jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java create mode 100644 jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index 626ce7998ff..b5853973e22 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -51,8 +51,6 @@ import org.eclipse.jetty.util.thread.Scheduler; public class HTTP2Client extends ContainerLifeCycle { private final Queue sessions = new ConcurrentLinkedQueue<>(); - private final Executor executor; - private final Scheduler scheduler; private final SelectorManager selector; private final ByteBufferPool byteBufferPool; @@ -63,9 +61,8 @@ public class HTTP2Client extends ContainerLifeCycle public HTTP2Client(Executor executor) { - this.executor = executor; addBean(executor); - this.scheduler = new ScheduledExecutorScheduler(); + Scheduler scheduler = new ScheduledExecutorScheduler(); addBean(scheduler, true); this.selector = new ClientSelectorManager(executor, scheduler); addBean(selector, true); @@ -121,7 +118,7 @@ public class HTTP2Client extends ContainerLifeCycle { Context context = (Context)attachment; Generator generator = new Generator(byteBufferPool, 4096); - HTTP2Session session = new HTTP2ClientSession(endpoint, generator, context.listener, new HTTP2FlowControl(), 65535); + HTTP2Session session = new HTTP2ClientSession(endpoint, generator, context.listener, new HTTP2FlowControl(65535)); Parser parser = new Parser(byteBufferPool, session); Connection connection = new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, 8192, session); context.promise.succeeded(session); diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index a4a00885100..7625dd748c8 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -34,9 +35,9 @@ public class HTTP2ClientSession extends HTTP2Session { private static final Logger LOG = Log.getLogger(HTTP2ClientSession.class); - public HTTP2ClientSession(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int initialWindowSize) + public HTTP2ClientSession(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl) { - super(endPoint, generator, listener, flowControl, initialWindowSize, 1); + super(endPoint, generator, listener, flowControl, 1); } @Override @@ -52,7 +53,7 @@ public class HTTP2ClientSession extends HTTP2Session else { stream.updateClose(frame.isEndStream(), false); - stream.process(frame); + stream.process(frame, Callback.Adapter.INSTANCE); notifyHeaders(stream, frame); if (stream.isClosed()) removeStream(stream, false); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java new file mode 100644 index 00000000000..8faf26193c7 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -0,0 +1,106 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServlet; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.After; + +public class AbstractTest +{ + private ServerConnector connector; + private String path = "/test"; + private HTTP2Client client; + private Server server; + + protected void startServer(HttpServlet servlet) throws Exception + { + prepareServer(new HTTP2ServerConnectionFactory(new HttpConfiguration())); + + ServletContextHandler context = new ServletContextHandler(server, "/"); + context.addServlet(new ServletHolder(servlet), path); + + prepareClient(); + server.start(); + } + + protected void startServer(Session.Listener listener) throws Exception + { + prepareServer(new RawHTTP2ServerConnectionFactory(listener)); + prepareClient(); + server.start(); + } + + private void prepareServer(ConnectionFactory connectionFactory) + { + QueuedThreadPool serverExecutor = new QueuedThreadPool(); + serverExecutor.setName("server"); + server = new Server(serverExecutor); + connector = new ServerConnector(server, connectionFactory); + server.addConnector(connector); + } + + private void prepareClient() + { + QueuedThreadPool clientExecutor = new QueuedThreadPool(); + clientExecutor.setName("client"); + client = new HTTP2Client(clientExecutor); + server.addBean(client); + } + + protected Session newClient(Session.Listener listener) throws Exception + { + String host = "localhost"; + int port = connector.getLocalPort(); + InetSocketAddress address = new InetSocketAddress(host, port); + FuturePromise promise = new FuturePromise<>(); + client.connect(address, listener, promise); + return promise.get(5, TimeUnit.SECONDS); + } + + @After + public void dispose() throws Exception + { + server.stop(); + } + + protected MetaData.Request newRequest(String method, HttpFields fields) + { + String host = "localhost"; + int port = connector.getLocalPort(); + String authority = host + ":" + port; + return new MetaData.Request(HttpScheme.HTTP, method, authority, host, port, path, fields); + } +} diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java new file mode 100644 index 00000000000..588994c04a1 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java @@ -0,0 +1,33 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class EmptyHttpServlet extends HttpServlet +{ + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + } +} diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java new file mode 100644 index 00000000000..327cdde1c89 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -0,0 +1,495 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FuturePromise; +import org.junit.Assert; +import org.junit.Test; + +public class FlowControlTest extends AbstractTest +{ + @Test + public void testFlowControlWithConcurrentSettings() throws Exception + { + // Initial window is 64 KiB. We allow the client to send 1024 B + // then we change the window to 512 B. At this point, the client + // must stop sending data (although the initial window allows it). + + final int size = 512; + final CountDownLatch dataLatch = new CountDownLatch(1); + final AtomicReference callbackRef = new AtomicReference<>(); + startServer(new Session.Listener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) + { + HttpFields fields = new HttpFields(); + MetaData.Response response = new MetaData.Response(200, fields); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + + return new Stream.Listener.Adapter() + { + private final AtomicInteger dataFrames = new AtomicInteger(); + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + int dataFrameCount = dataFrames.incrementAndGet(); + if (dataFrameCount == 1) + { + callbackRef.set(callback); + Map settings = new HashMap<>(); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, size); + stream.getSession().settings(new SettingsFrame(settings, false), Callback.Adapter.INSTANCE); + // Do not succeed the callback here. + } + else if (dataFrameCount > 1) + { + // Consume the data. + callback.succeeded(); + dataLatch.countDown(); + } + } + }; + } + }); + + // Two SETTINGS frames, the initial one and the one we send. + final CountDownLatch settingsLatch = new CountDownLatch(2); + Session client = newClient(new Session.Listener.Adapter() + { + @Override + public void onSettings(Session session, SettingsFrame frame) + { + settingsLatch.countDown(); + } + }); + + MetaData.Request request = newRequest("POST", new HttpFields()); + FuturePromise promise = new FuturePromise<>(); + client.newStream(new HeadersFrame(0, request, null, false), promise, new Stream.Listener.Adapter()); + Stream stream = promise.get(5, TimeUnit.SECONDS); + + // Send first chunk that exceeds the window. + stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(size * 2), false), Callback.Adapter.INSTANCE); + settingsLatch.await(5, TimeUnit.SECONDS); + + // Send the second chunk of data, must not arrive since we're flow control stalled on the client. + stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(size * 2), false), Callback.Adapter.INSTANCE); + Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); + + // Consume the data arrived to server, this will resume flow control on the client. + callbackRef.get().succeeded(); + + Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); + } + +/* + @Test + public void testServerFlowControlOneBigWrite() throws Exception + { + final int windowSize = 1536; + final int length = 5 * windowSize; + final CountDownLatch settingsLatch = new CountDownLatch(1); + Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() + { + @Override + public void onSettings(Session session, SettingsInfo settingsInfo) + { + settingsLatch.countDown(); + } + + @Override + public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) + { + stream.reply(new ReplyInfo(false), new Callback.Adapter()); + stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter()); + return null; + } + }), null); + + Settings settings = new Settings(); + settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); + session.settings(new SettingsInfo(settings)); + + Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); + + final Exchanger exchanger = new Exchanger<>(); + session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() + { + private AtomicInteger dataFrames = new AtomicInteger(); + + @Override + public void onData(Stream stream, DataInfo dataInfo) + { + try + { + int dataFrames = this.dataFrames.incrementAndGet(); + if (dataFrames == 1) + { + // Do not consume nor read from the data frame. + // We should then be flow-control stalled + exchanger.exchange(dataInfo); + } + else if (dataFrames == 2) + { + // Read but not consume, we should be flow-control stalled + dataInfo.asByteBuffer(false); + exchanger.exchange(dataInfo); + } + else if (dataFrames == 3) + { + // Consume partially, we should be flow-control stalled + dataInfo.consumeInto(ByteBuffer.allocate(dataInfo.length() / 2)); + exchanger.exchange(dataInfo); + } + else if (dataFrames == 4 || dataFrames == 5) + { + // Consume totally + dataInfo.asByteBuffer(true); + exchanger.exchange(dataInfo); + } + else + { + Assert.fail(); + } + } + catch (InterruptedException x) + { + throw new SPDYException(x); + } + } + }); + + DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + checkThatWeAreFlowControlStalled(exchanger); + + Assert.assertEquals(windowSize, dataInfo.available()); + Assert.assertEquals(0, dataInfo.consumed()); + dataInfo.asByteBuffer(true); + + dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + checkThatWeAreFlowControlStalled(exchanger); + + Assert.assertEquals(0, dataInfo.available()); + Assert.assertEquals(0, dataInfo.consumed()); + dataInfo.consume(dataInfo.length()); + + dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + checkThatWeAreFlowControlStalled(exchanger); + + Assert.assertEquals(dataInfo.length() / 2, dataInfo.consumed()); + dataInfo.asByteBuffer(true); + + dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); + // Check that we are not flow control stalled + dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); + } + + @Test + public void testClientFlowControlOneBigWrite() throws Exception + { + final int windowSize = 1536; + final Exchanger exchanger = new Exchanger<>(); + final CountDownLatch settingsLatch = new CountDownLatch(1); + Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() + { + @Override + public void onConnect(Session session) + { + Settings settings = new Settings(); + settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); + session.settings(new SettingsInfo(settings), new FutureCallback()); + } + + @Override + public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) + { + stream.reply(new ReplyInfo(false), new Callback.Adapter()); + return new StreamFrameListener.Adapter() + { + private AtomicInteger dataFrames = new AtomicInteger(); + + @Override + public void onData(Stream stream, DataInfo dataInfo) + { + try + { + int dataFrames = this.dataFrames.incrementAndGet(); + if (dataFrames == 1) + { + // Do not consume nor read from the data frame. + // We should then be flow-control stalled + exchanger.exchange(dataInfo); + } + else if (dataFrames == 2) + { + // Read but not consume, we should be flow-control stalled + dataInfo.asByteBuffer(false); + exchanger.exchange(dataInfo); + } + else if (dataFrames == 3) + { + // Consume partially, we should be flow-control stalled + dataInfo.consumeInto(ByteBuffer.allocate(dataInfo.length() / 2)); + exchanger.exchange(dataInfo); + } + else if (dataFrames == 4 || dataFrames == 5) + { + // Consume totally + dataInfo.asByteBuffer(true); + exchanger.exchange(dataInfo); + } + else + { + Assert.fail(); + } + } + catch (InterruptedException x) + { + throw new SPDYException(x); + } + } + }; + } + }), new SessionFrameListener.Adapter() + { + @Override + public void onSettings(Session session, SettingsInfo settingsInfo) + { + settingsLatch.countDown(); + } + }); + + Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); + + Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); + final int length = 5 * windowSize; + stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter()); + + DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + checkThatWeAreFlowControlStalled(exchanger); + + Assert.assertEquals(windowSize, dataInfo.available()); + Assert.assertEquals(0, dataInfo.consumed()); + dataInfo.asByteBuffer(true); + + dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + checkThatWeAreFlowControlStalled(exchanger); + + Assert.assertEquals(0, dataInfo.available()); + Assert.assertEquals(0, dataInfo.consumed()); + dataInfo.consume(dataInfo.length()); + + dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + checkThatWeAreFlowControlStalled(exchanger); + + Assert.assertEquals(dataInfo.length() / 2, dataInfo.consumed()); + dataInfo.asByteBuffer(true); + + dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); + // Check that we are not flow control stalled + dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); + } + + @Test + public void testStreamsStalledDoesNotStallOtherStreams() throws Exception + { + final int windowSize = 1024; + final CountDownLatch settingsLatch = new CountDownLatch(1); + Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() + { + @Override + public void onSettings(Session session, SettingsInfo settingsInfo) + { + settingsLatch.countDown(); + } + + @Override + public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) + { + stream.reply(new ReplyInfo(false), new Callback.Adapter()); + stream.data(new BytesDataInfo(new byte[windowSize * 2], true), new Callback.Adapter()); + return null; + } + }), null); + Settings settings = new Settings(); + settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); + session.settings(new SettingsInfo(settings)); + + Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); + + final CountDownLatch latch = new CountDownLatch(3); + final AtomicReference dataInfoRef1 = new AtomicReference<>(); + final AtomicReference dataInfoRef2 = new AtomicReference<>(); + session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() + { + private final AtomicInteger dataFrames = new AtomicInteger(); + + @Override + public void onData(Stream stream, DataInfo dataInfo) + { + int frames = dataFrames.incrementAndGet(); + if (frames == 1) + { + // Do not consume it to stall flow control + dataInfoRef1.set(dataInfo); + } + else + { + dataInfo.consume(dataInfo.length()); + if (dataInfo.isClose()) + latch.countDown(); + } + } + }); + session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() + { + private final AtomicInteger dataFrames = new AtomicInteger(); + + @Override + public void onData(Stream stream, DataInfo dataInfo) + { + int frames = dataFrames.incrementAndGet(); + if (frames == 1) + { + // Do not consume it to stall flow control + dataInfoRef2.set(dataInfo); + } + else + { + dataInfo.consume(dataInfo.length()); + if (dataInfo.isClose()) + latch.countDown(); + } + } + }); + session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() + { + @Override + public void onData(Stream stream, DataInfo dataInfo) + { + DataInfo dataInfo1 = dataInfoRef1.getAndSet(null); + if (dataInfo1 != null) + dataInfo1.consume(dataInfo1.length()); + DataInfo dataInfo2 = dataInfoRef2.getAndSet(null); + if (dataInfo2 != null) + dataInfo2.consume(dataInfo2.length()); + dataInfo.consume(dataInfo.length()); + if (dataInfo.isClose()) + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testSendBigFileWithoutFlowControl() throws Exception + { + testSendBigFile(SPDY.V2); + } + + @Test + public void testSendBigFileWithFlowControl() throws Exception + { + testSendBigFile(SPDY.V3); + } + + private void testSendBigFile(short version) throws Exception + { + final int dataSize = 1024 * 1024; + final ByteBufferDataInfo bigByteBufferDataInfo = new ByteBufferDataInfo(ByteBuffer.allocate(dataSize),false); + final CountDownLatch allDataReceivedLatch = new CountDownLatch(1); + + Session session = startClient(version, startServer(version, new ServerSessionFrameListener.Adapter() + { + @Override + public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) + { + stream.reply(new ReplyInfo(false), new Callback.Adapter()); + stream.data(bigByteBufferDataInfo, new Callback.Adapter()); + return null; + } + }),new SessionFrameListener.Adapter()); + + session.syn(new SynInfo(new Fields(), false),new StreamFrameListener.Adapter() + { + private int dataBytesReceived; + + @Override + public void onData(Stream stream, DataInfo dataInfo) + { + dataBytesReceived = dataBytesReceived + dataInfo.length(); + dataInfo.consume(dataInfo.length()); + if (dataBytesReceived == dataSize) + allDataReceivedLatch.countDown(); + } + }); + + assertThat("all data bytes have been received by the client", allDataReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); + } + + private void checkThatWeAreFlowControlStalled(final Exchanger exchanger) + { + expectException(TimeoutException.class, new Callable() + { + @Override + public DataInfo call() throws Exception + { + return exchanger.exchange(null, 1, TimeUnit.SECONDS); + } + }); + } + + private void expectException(Class exception, Callable command) + { + try + { + command.call(); + Assert.fail(); + } + catch (Exception x) + { + Assert.assertSame(exception, x.getClass()); + } + } +*/ +} diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index 3af73779ed0..4e7e91d5254 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.http2.client; import java.io.IOException; -import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; @@ -30,83 +29,30 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.hpack.MetaData; -import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.After; import org.junit.Assert; import org.junit.Test; -public class HTTP2Test +public class HTTP2Test extends AbstractTest { - private Server server; - private ServerConnector connector; - private String path; - private HTTP2Client client; - - private void startServer(HttpServlet servlet) throws Exception - { - QueuedThreadPool serverExecutor = new QueuedThreadPool(); - serverExecutor.setName("server"); - server = new Server(serverExecutor); - connector = new ServerConnector(server, new HTTP2ServerConnectionFactory(new HttpConfiguration())); - server.addConnector(connector); - - ServletContextHandler context = new ServletContextHandler(server, "/"); - path = "/test"; - context.addServlet(new ServletHolder(servlet), path); - - QueuedThreadPool clientExecutor = new QueuedThreadPool(); - clientExecutor.setName("client"); - client = new HTTP2Client(clientExecutor); - server.addBean(client); - - server.start(); - } - - @After - public void dispose() throws Exception - { - server.stop(); - } - @Test public void testRequestNoContentResponseNoContent() throws Exception { - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException - { - } - }); + startServer(new EmptyHttpServlet()); - String host = "localhost"; - int port = connector.getLocalPort(); - String authority = host + ":" + port; - InetSocketAddress address = new InetSocketAddress(host, port); - FuturePromise promise = new FuturePromise<>(); - client.connect(address, new Session.Listener.Adapter(), promise); - Session session = promise.get(); + Session client = newClient(new Session.Listener.Adapter()); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", authority, host, port, path, fields); + MetaData.Request metaData = newRequest("GET", fields); HeadersFrame frame = new HeadersFrame(1, metaData, null, true); final CountDownLatch latch = new CountDownLatch(1); - session.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() + client.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() { @Override public void onHeaders(Stream stream, HeadersFrame frame) @@ -140,19 +86,13 @@ public class HTTP2Test } }); - String host = "localhost"; - int port = connector.getLocalPort(); - String authority = host + ":" + port; - InetSocketAddress address = new InetSocketAddress(host, port); - FuturePromise promise = new FuturePromise<>(); - client.connect(address, new Session.Listener.Adapter(), promise); - Session session = promise.get(); + Session client = newClient(new Session.Listener.Adapter()); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", authority, host, port, path, fields); + MetaData.Request metaData = newRequest("GET", fields); HeadersFrame frame = new HeadersFrame(1, metaData, null, true); final CountDownLatch latch = new CountDownLatch(2); - session.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() + client.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() { @Override public void onHeaders(Stream stream, HeadersFrame frame) @@ -177,6 +117,7 @@ public class HTTP2Test Assert.assertTrue(frame.isEndStream()); Assert.assertEquals(ByteBuffer.wrap(content), frame.getData()); + callback.succeeded(); latch.countDown(); } }); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java index c5b029ac9b6..44b29c358b0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java @@ -18,11 +18,21 @@ package org.eclipse.jetty.http2; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; + public interface FlowControl { public void onNewStream(IStream stream); - public int getWindowSize(ISession session); + public int getInitialWindowSize(); - public void setWindowSize(ISession session, int windowSize); + public void updateInitialWindowSize(ISession session, int initialWindowSize); + + public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame); + + public void onDataReceived(ISession session, IStream stream, int length); + + public void onDataConsumed(ISession session, IStream stream, int length); + + public void onDataSent(ISession session, IStream stream, int length); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index 7845025038e..492c0679b2d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -18,21 +18,84 @@ package org.eclipse.jetty.http2; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; +import org.eclipse.jetty.util.Callback; + public class HTTP2FlowControl implements FlowControl { + private volatile int initialWindowSize; + + public HTTP2FlowControl(int initialWindowSize) + { + this.initialWindowSize = initialWindowSize; + } + @Override public void onNewStream(IStream stream) { + stream.updateWindowSize(initialWindowSize); } @Override - public int getWindowSize(ISession session) + public int getInitialWindowSize() { - return 0; + return initialWindowSize; } @Override - public void setWindowSize(ISession session, int windowSize) + public void updateInitialWindowSize(ISession session, int initialWindowSize) { + int windowSize = this.initialWindowSize; + this.initialWindowSize = initialWindowSize; + + int delta = initialWindowSize - windowSize; + + // Update the sessions's window size. + session.updateWindowSize(delta); + + // Update the streams' window size. + for (Stream stream : session.getStreams()) + ((IStream)stream).updateWindowSize(delta); + } + + @Override + public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame) + { + if (frame.getStreamId() > 0) + { + if (stream != null) + stream.updateWindowSize(frame.getWindowDelta()); + } + else + { + session.updateWindowSize(frame.getWindowDelta()); + } + } + + @Override + public void onDataReceived(ISession session, IStream stream, int length) + { + } + + @Override + public void onDataConsumed(ISession session, IStream stream, int length) + { + // This is the algorithm for flow control. + // This method is called when a whole flow controlled frame has been consumed. + // We currently send a WindowUpdate every time, even if the frame was very small. + // Other policies may send the WindowUpdate only upon reaching a threshold. + + // Negative streamId allow for generation of bytes for both stream and session + int streamId = stream != null ? -stream.getId() : 0; + WindowUpdateFrame frame = new WindowUpdateFrame(streamId, length); + session.frame(stream, frame, Callback.Adapter.INSTANCE); + } + + @Override + public void onDataSent(ISession session, IStream stream, int length) + { + stream.getSession().updateWindowSize(length); + stream.updateWindowSize(length); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index d3856e8c095..7295cfd18f5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -24,9 +24,11 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; @@ -45,6 +47,7 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.Atomics; @@ -72,23 +75,24 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final AtomicInteger streamIds = new AtomicInteger(); private final AtomicInteger lastStreamId = new AtomicInteger(); private final AtomicInteger streamCount = new AtomicInteger(); - private final Flusher flusher = new Flusher(); + private final AtomicInteger windowSize = new AtomicInteger(); private final EndPoint endPoint; private final Generator generator; private final Listener listener; private final FlowControl flowControl; - private final int initialWindowSize; + private final Flusher flusher; private volatile int maxStreamCount; - public HTTP2Session(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int initialWindowSize, int initialStreamId) + public HTTP2Session(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int initialStreamId) { this.endPoint = endPoint; this.generator = generator; this.listener = listener; this.flowControl = flowControl; - this.initialWindowSize = initialWindowSize; + this.flusher = new Flusher(4); this.maxStreamCount = -1; this.streamIds.set(initialStreamId); + this.windowSize.set(flowControl.getInitialWindowSize()); } public Generator getGenerator() @@ -96,11 +100,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return generator; } - public int getInitialWindowSize() - { - return initialWindowSize; - } - public int getMaxStreamCount() { return maxStreamCount; @@ -112,14 +111,24 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } @Override - public boolean onData(DataFrame frame) + public boolean onData(final DataFrame frame) { int streamId = frame.getStreamId(); - IStream stream = getStream(streamId); + final IStream stream = getStream(streamId); if (stream != null) { stream.updateClose(frame.isEndStream(), false); - return stream.process(frame); + flowControl.onDataReceived(this, stream, frame.getFlowControlledLength()); + return stream.process(frame, new Callback.Adapter() + { + @Override + public void succeeded() + { + int consumed = frame.getFlowControlledLength(); + LOG.debug("Flow control: {} consumed on {}", consumed, stream); + flowControl.onDataConsumed(HTTP2Session.this, stream, consumed); + } + }); } else { @@ -156,8 +165,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (settings.containsKey(SettingsFrame.INITIAL_WINDOW_SIZE)) { int windowSize = settings.get(SettingsFrame.INITIAL_WINDOW_SIZE); - setWindowSize(windowSize); - LOG.debug("Updated window size to {}", windowSize); + flowControl.updateInitialWindowSize(this, windowSize); + LOG.debug("Updated initial window size to {}", windowSize); } // TODO: handle other settings notifySettings(this, frame); @@ -202,6 +211,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onWindowUpdate(WindowUpdateFrame frame) { + int streamId = frame.getStreamId(); + IStream stream = null; + if (streamId > 0) + stream = getStream(streamId); + flowControl.onWindowUpdate(this, stream, frame); + + // Flush stalled data. + flusher.iterate(); return false; } @@ -231,7 +248,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } stream.updateClose(frame.isEndStream(), true); stream.setListener(listener); - flusher.offer(generator.generate(frame, new PromiseCallback<>(promise, stream))); + + FlusherEntry entry = new FlusherEntry(stream, frame, new PromiseCallback<>(promise, stream)); + flusher.offer(entry); } // Iterate outside the synchronized block. flusher.iterate(); @@ -240,19 +259,19 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void settings(SettingsFrame frame, Callback callback) { - frame(frame, callback); + frame(null, frame, callback); } @Override public void ping(PingFrame frame, Callback callback) { - frame(frame, callback); + frame(null, frame, callback); } @Override public void reset(ResetFrame frame, Callback callback) { - frame(frame, callback); + frame(null, frame, callback); } @Override @@ -261,14 +280,19 @@ public abstract class HTTP2Session implements ISession, Parser.Listener byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); LOG.debug("Sending {}: {}", frame.getType(), reason); - frame(frame, callback); + frame(null, frame, callback); } @Override - public void frame(Frame frame, Callback callback) + public void frame(IStream stream, Frame frame, Callback callback) { - Generator.LeaseCallback lease = generator.generate(frame, callback); - flusher.flush(lease); + int flowControlledLength = frame.getFlowControlledLength(); + if (flowControlledLength > 0) + callback = new FlowControlCallback(stream, flowControlledLength, callback); + // We want to generate as late as possible to allow re-prioritization. + FlusherEntry entry = new FlusherEntry(stream, frame, callback); + LOG.debug("Sending {}", frame); + flusher.flush(entry); } protected void disconnect() @@ -281,9 +305,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { IStream stream = newStream(frame); int streamId = stream.getId(); - updateLastStreamId(streamId); if (streams.putIfAbsent(streamId, stream) == null) { + flowControl.onNewStream(stream); LOG.debug("Created local {}", stream); return stream; } @@ -317,6 +341,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (streams.putIfAbsent(streamId, stream) == null) { updateLastStreamId(streamId); + flowControl.onNewStream(stream); LOG.debug("Created remote {}", stream); return stream; } @@ -359,16 +384,24 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return streams.get(streamId); } + protected int getWindowSize() + { + return windowSize.get(); + } + + @Override + public int updateWindowSize(int delta) + { + int oldSize = windowSize.getAndAdd(delta); + LOG.debug("Flow control: updated window {} -> {} for {}", oldSize, oldSize + delta, this); + return oldSize; + } + private void updateLastStreamId(int streamId) { Atomics.updateMax(lastStreamId, streamId); } - public void setWindowSize(int initialWindowSize) - { - flowControl.setWindowSize(this, initialWindowSize); - } - protected Stream.Listener notifyNewStream(Stream stream, HeadersFrame frame) { try @@ -394,13 +427,30 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } + @Override + public String toString() + { + return String.format("%s@%x{queueSize=%d,windowSize=%s,streams=%d}", getClass().getSimpleName(), + hashCode(), flusher.getQueueSize(), windowSize, streams.size()); + } + private class Flusher extends IteratingCallback { - private final Queue queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH); - private Generator.LeaseCallback active; + private final ArrayQueue queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH); + private final Set stalled = new HashSet<>(); + private final List reset = new ArrayList<>(); + private final ByteBufferPool.Lease lease = new ByteBufferPool.Lease(generator.getByteBufferPool()); + private final int maxGather; + private final List active; private boolean closed; - private void offer(Generator.LeaseCallback lease) + public Flusher(int maxGather) + { + this.maxGather = maxGather; + this.active = new ArrayList<>(maxGather); + } + + private void offer(FlusherEntry entry) { boolean fail = false; synchronized (queue) @@ -408,31 +458,108 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (closed) fail = true; else - queue.offer(lease); + queue.offer(entry); } if (fail) - fail(lease); + closed(entry); } - private void flush(Generator.LeaseCallback lease) + public int getQueueSize() { - offer(lease); + synchronized (queue) + { + return queue.size(); + } + } + + private void flush(FlusherEntry entry) + { + offer(entry); iterate(); } @Override protected Action process() throws Exception { - Generator.LeaseCallback current = null; synchronized (queue) { - if (!closed) - current = active = queue.poll(); + if (closed) + return Action.IDLE; + + int nonStalledIndex = 0; + int size = queue.size(); + while (nonStalledIndex < size) + { + FlusherEntry entry = queue.get(nonStalledIndex); + IStream stream = entry.getStream(); + boolean flowControlled = entry.getFrame().getFlowControlledLength() > 0; + if (flowControlled) + { + // Is the session stalled ? + if (getWindowSize() <= 0) + { + LOG.debug("Flow control: session stalled {}", HTTP2Session.this); + ++nonStalledIndex; + // There may be *non* flow controlled frames to send. + continue; + } + + if (stream != null) + { + // Is it a frame belonging to an already stalled stream ? + if (stalled.contains(stream)) + { + ++nonStalledIndex; + continue; + } + + // Is the stream stalled ? + if (stream.getWindowSize() <= 0) + { + LOG.debug("Flow control: stream stalled {}", stream); + stalled.add(stream); + ++nonStalledIndex; + continue; + } + } + } + + // We will be possibly writing this frame. + queue.remove(nonStalledIndex); + --size; + + // Has the stream been reset ? + if (stream != null && stream.isReset() && flowControlled) + { + reset.add(entry); + continue; + } + + active.add(entry); + if (active.size() == maxGather) + break; + } + stalled.clear(); } - if (current == null) + + for (int i = 0; i < reset.size(); ++i) + { + FlusherEntry entry = reset.get(i); + // TODO: introduce a StreamResetException ? + entry.failed(new IllegalStateException()); + } + reset.clear(); + + if (active.isEmpty()) return Action.IDLE; - List byteBuffers = current.getByteBuffers(); + for (int i = 0; i < active.size(); ++i) + { + FlusherEntry entry = active.get(i); + generator.generate(lease, entry.getFrame()); + } + + List byteBuffers = lease.getByteBuffers(); endPoint.write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()])); return Action.SCHEDULED; } @@ -440,25 +567,38 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void succeeded() { - active.succeeded(); + lease.recycle(); + for (int i = 0; i < active.size(); ++i) + { + FlusherEntry entry = active.get(i); + entry.succeeded(); + } + active.clear(); super.succeeded(); } @Override public void failed(Throwable x) { - active.failed(x); + lease.recycle(); + for (int i = 0; i < active.size(); ++i) + { + FlusherEntry entry = active.get(i); + entry.failed(x); + } + active.clear(); super.failed(x); } @Override protected void completed() { + throw new IllegalStateException(); } public void close() { - Queue queued; + Queue queued; synchronized (queue) { closed = true; @@ -467,19 +607,55 @@ public abstract class HTTP2Session implements ISession, Parser.Listener while (true) { - Generator.LeaseCallback item = queued.poll(); + FlusherEntry item = queued.poll(); if (item == null) break; - fail(item); + closed(item); } } - protected void fail(Generator.LeaseCallback item) + protected void closed(FlusherEntry item) { item.failed(new ClosedChannelException()); } } + private class FlusherEntry implements Callback + { + private final IStream stream; + private final Frame frame; + private final Callback callback; + + private FlusherEntry(IStream stream, Frame frame, Callback callback) + { + this.stream = stream; + this.frame = frame; + this.callback = callback; + } + + public IStream getStream() + { + return stream; + } + + public Frame getFrame() + { + return frame; + } + + @Override + public void succeeded() + { + callback.succeeded(); + } + + @Override + public void failed(Throwable x) + { + callback.failed(x); + } + } + public class PromiseCallback implements Callback { private final Promise promise; @@ -503,4 +679,31 @@ public abstract class HTTP2Session implements ISession, Parser.Listener promise.failed(x); } } + + private class FlowControlCallback implements Callback + { + private final IStream stream; + private final int length; + private final Callback callback; + + private FlowControlCallback(IStream stream, int length, Callback callback) + { + this.stream = stream; + this.length = length; + this.callback = callback; + } + + @Override + public void succeeded() + { + flowControl.onDataSent(HTTP2Session.this, stream, -length); + callback.succeeded(); + } + + @Override + public void failed(Throwable x) + { + callback.failed(x); + } + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 122eaea4623..a0a8e79752f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http2.frames.DataFrame; @@ -35,9 +36,11 @@ public class HTTP2Stream implements IStream private final AtomicReference> attributes = new AtomicReference<>(); private final AtomicReference closeState = new AtomicReference<>(CloseState.NOT_CLOSED); + private final AtomicInteger windowSize = new AtomicInteger(); private final ISession session; private final HeadersFrame frame; private Listener listener; + private volatile boolean reset = false; public HTTP2Stream(ISession session, HeadersFrame frame) { @@ -60,13 +63,13 @@ public class HTTP2Stream implements IStream @Override public void headers(HeadersFrame frame, Callback callback) { - session.frame(frame, callback); + session.frame(this, frame, callback); } @Override public void data(DataFrame frame, Callback callback) { - session.frame(frame, callback); + session.frame(this, frame, callback); } @Override @@ -87,6 +90,12 @@ public class HTTP2Stream implements IStream return attributes().remove(key); } + @Override + public boolean isReset() + { + return reset; + } + @Override public boolean isClosed() { @@ -120,20 +129,27 @@ public class HTTP2Stream implements IStream } @Override - public boolean process(Frame frame) + public boolean process(Frame frame, Callback callback) { switch (frame.getType()) { case DATA: { - return notifyData((DataFrame)frame); + return notifyData((DataFrame)frame, callback); } case HEADERS: { return false; } + case RST_STREAM: + { + reset = true; + return false; + } default: + { throw new UnsupportedOperationException(); + } } } @@ -182,27 +198,28 @@ public class HTTP2Stream implements IStream } } - protected boolean notifyData(DataFrame frame) + @Override + public int getWindowSize() + { + return windowSize.get(); + } + + @Override + public int updateWindowSize(int delta) + { + int oldSize = windowSize.getAndAdd(delta); + LOG.debug("Flow control: updated window {} -> {} for {}", oldSize, oldSize + delta, this); + return oldSize; + } + + protected boolean notifyData(DataFrame frame, Callback callback) { final Listener listener = this.listener; if (listener == null) return false; try { - listener.onData(this, frame, new Callback() - { - @Override - public void succeeded() - { - // TODO: notify flow control - } - - @Override - public void failed(Throwable x) - { - // TODO: bail out - } - }); + listener.onData(this, frame, callback); return false; } catch (Throwable x) @@ -215,7 +232,8 @@ public class HTTP2Stream implements IStream @Override public String toString() { - return String.format("%s@%x", getClass().getSimpleName(), hashCode()); + return String.format("%s@%x{id=%d,windowSize=%s,%s}", getClass().getSimpleName(), + hashCode(), getId(), windowSize, closeState); } private enum CloseState diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index e3c4a11c9b0..916dddc6cca 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -27,5 +27,7 @@ public interface ISession extends Session @Override IStream getStream(int streamId); - public void frame(Frame frame, Callback callback); + public void frame(IStream stream, Frame frame, Callback callback); + + public int updateWindowSize(int delta); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index d7cc0222965..5bd23056bb6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.util.Callback; public interface IStream extends Stream { @@ -30,7 +31,7 @@ public interface IStream extends Stream public void setListener(Listener listener); - public boolean process(Frame frame); + public boolean process(Frame frame, Callback callback); /** * Updates the close state of this stream. @@ -42,4 +43,8 @@ public interface IStream extends Stream * that ends the stream). */ public void updateClose(boolean update, boolean local); + + public int getWindowSize(); + + public int updateWindowSize(int delta); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index 9afc09570b7..5e72e05464a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -38,6 +38,8 @@ public interface Stream public Object removeAttribute(String key); + public boolean isReset(); + public boolean isClosed(); // TODO: see SPDY's Stream @@ -63,6 +65,7 @@ public interface Stream @Override public void onData(Stream stream, DataFrame frame, Callback callback) { + callback.succeeded(); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java index e9e84cdc3dd..3bc7ac73814 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -24,14 +24,21 @@ public class DataFrame extends Frame { private final int streamId; private final ByteBuffer data; - private boolean endStream; + private final boolean endStream; + private final int length; public DataFrame(int streamId, ByteBuffer data, boolean endStream) + { + this(streamId, data, endStream, 0); + } + + public DataFrame(int streamId, ByteBuffer data, boolean endStream, int padding) { super(FrameType.DATA); this.streamId = streamId; this.data = data; this.endStream = endStream; + this.length = data.remaining() + padding; } public int getStreamId() @@ -48,4 +55,16 @@ public class DataFrame extends Frame { return endStream; } + + @Override + public int getFlowControlledLength() + { + return length; + } + + @Override + public String toString() + { + return String.format("%s{length:%d/%d}", super.toString(), data.remaining(), length); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java index 782b6480c98..150d97aefc9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java @@ -23,7 +23,7 @@ public abstract class Frame public static final int HEADER_LENGTH = 8; public static final int MAX_LENGTH = 0x3F_FF; - private FrameType type; + private final FrameType type; protected Frame(FrameType type) { @@ -35,6 +35,11 @@ public abstract class Frame return type; } + public int getFlowControlledLength() + { + return 0; + } + @Override public String toString() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index 3ef4497b3ed..d7f74ff2922 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -26,7 +26,6 @@ import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; public class DataGenerator extends FrameGenerator { @@ -36,7 +35,7 @@ public class DataGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { DataFrame dataFrame = (DataFrame)frame; generateData(lease, dataFrame.getStreamId(), dataFrame.getData(), dataFrame.isEndStream(), false, null); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java index e8039de130c..ae345710c23 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java @@ -23,7 +23,6 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.util.Callback; public abstract class FrameGenerator { @@ -34,7 +33,7 @@ public abstract class FrameGenerator this.headerGenerator = headerGenerator; } - public abstract void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback); + public abstract void generate(ByteBufferPool.Lease lease, Frame frame); protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int length, int flags, int streamId) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index ab5c6396bfe..61c85d4fe96 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -22,7 +22,6 @@ import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.util.Callback; public class Generator { @@ -59,40 +58,18 @@ public class Generator } + public ByteBufferPool getByteBufferPool() + { + return byteBufferPool; + } + public int getHeaderTableSize() { return headerTableSize; } - public LeaseCallback generate(Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { - LeaseCallback lease = new LeaseCallback(byteBufferPool, callback); - generators[frame.getType().getType()].generate(lease, frame, callback); - return lease; - } - - public static class LeaseCallback extends ByteBufferPool.Lease implements Callback - { - private final Callback callback; - - public LeaseCallback(ByteBufferPool byteBufferPool, Callback callback) - { - super(byteBufferPool); - this.callback = callback; - } - - @Override - public void succeeded() - { - recycle(); - callback.succeeded(); - } - - @Override - public void failed(Throwable x) - { - recycle(); - callback.failed(x); - } + generators[frame.getType().getType()].generate(lease, frame); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index 0339c4904d2..121059875f0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -26,7 +26,6 @@ import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; public class GoAwayGenerator extends FrameGenerator { @@ -36,7 +35,7 @@ public class GoAwayGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { GoAwayFrame goAwayFrame = (GoAwayFrame)frame; generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index 7c1accb284d..e8e19a6be0c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -28,7 +28,6 @@ import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; public class HeadersGenerator extends FrameGenerator { @@ -41,7 +40,7 @@ public class HeadersGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { HeadersFrame headersFrame = (HeadersFrame)frame; generate(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream(), null); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java index 940bb896953..ec5db1a151a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java @@ -26,7 +26,6 @@ import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; public class PingGenerator extends FrameGenerator { @@ -36,7 +35,7 @@ public class PingGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { PingFrame pingFrame = (PingFrame)frame; generatePing(lease, pingFrame.getPayload(), pingFrame.isReply()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java index 8364a55ddaf..4ebb52d715f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java @@ -26,7 +26,6 @@ import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; public class PriorityGenerator extends FrameGenerator { @@ -36,7 +35,7 @@ public class PriorityGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { PriorityFrame priorityFrame = (PriorityFrame)frame; generatePriority(lease, priorityFrame.getStreamId(), priorityFrame.getDependentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java index 48b792e0074..781f29346d0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java @@ -26,7 +26,6 @@ import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; public class ResetGenerator extends FrameGenerator { @@ -36,7 +35,7 @@ public class ResetGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { ResetFrame resetFrame = (ResetFrame)frame; generateReset(lease, resetFrame.getStreamId(), resetFrame.getError()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index 77f483b3e4e..43971341750 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -27,7 +27,6 @@ import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; public class SettingsGenerator extends FrameGenerator { @@ -37,7 +36,7 @@ public class SettingsGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { SettingsFrame settingsFrame = (SettingsFrame)frame; generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java index 099930371ee..e9be713989e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java @@ -26,7 +26,6 @@ import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; public class WindowUpdateGenerator extends FrameGenerator { @@ -36,7 +35,7 @@ public class WindowUpdateGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, Callback callback) + public void generate(ByteBufferPool.Lease lease, Frame frame) { WindowUpdateFrame windowUpdateFrame = (WindowUpdateFrame)frame; generateWindowUpdate(lease, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta()); @@ -44,15 +43,28 @@ public class WindowUpdateGenerator extends FrameGenerator public void generateWindowUpdate(ByteBufferPool.Lease lease, int streamId, int windowUpdate) { - if (streamId < 0) - throw new IllegalArgumentException("Invalid stream id: " + streamId); if (windowUpdate < 0) throw new IllegalArgumentException("Invalid window update: " + windowUpdate); + // A negative streamId means that we have to generate + // bytes for both the stream and session frames. + boolean both = false; + if (streamId < 0) + { + both = true; + streamId = -streamId; + } + + if (both) + { + ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flag.NONE, 0); + header.putInt(windowUpdate); + BufferUtil.flipToFlush(header, 0); + lease.append(header, true); + } + ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flag.NONE, streamId); - header.putInt(windowUpdate); - BufferUtil.flipToFlush(header, 0); lease.append(header, true); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index 84cff736310..4992f416103 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -49,7 +49,7 @@ public class DataBodyParser extends BodyParser notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame"); return false; } - return onData(BufferUtil.EMPTY_BUFFER, false); + return onData(BufferUtil.EMPTY_BUFFER, false, 0); } @Override @@ -116,7 +116,7 @@ public class DataBodyParser extends BodyParser if (length == 0) { state = State.PADDING; - if (onData(slice, false)) + if (onData(slice, false, paddingLength)) { return Result.ASYNC; } @@ -125,7 +125,7 @@ public class DataBodyParser extends BodyParser { // TODO: check the semantic of Flag.END_SEGMENT. // We got partial data, simulate a smaller frame, and stay in DATA state. - if (onData(slice, true)) + if (onData(slice, true, 0)) { return Result.ASYNC; } @@ -153,9 +153,9 @@ public class DataBodyParser extends BodyParser return Result.PENDING; } - private boolean onData(ByteBuffer buffer, boolean fragment) + private boolean onData(ByteBuffer buffer, boolean fragment, int padding) { - DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream()); + DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding); return notifyData(frame); } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java new file mode 100644 index 00000000000..4999a81be8c --- /dev/null +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -0,0 +1,79 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import org.eclipse.jetty.http2.HTTP2Connection; +import org.eclipse.jetty.http2.HTTP2FlowControl; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.http2.parser.ServerParser; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.AbstractConnectionFactory; +import org.eclipse.jetty.server.Connector; + +public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory +{ + private int headerTableSize = 4096; + private int initialWindowSize = 65535; + + public AbstractHTTP2ServerConnectionFactory() + { + super("h2-12"); + } + + public int getHeaderTableSize() + { + return headerTableSize; + } + + public void setHeaderTableSize(int headerTableSize) + { + this.headerTableSize = headerTableSize; + } + + public int getInitialWindowSize() + { + return initialWindowSize; + } + + public void setInitialWindowSize(int initialWindowSize) + { + this.initialWindowSize = initialWindowSize; + } + + @Override + public Connection newConnection(Connector connector, EndPoint endPoint) + { + Session.Listener listener = newSessionListener(connector, endPoint); + + Generator generator = new Generator(connector.getByteBufferPool(), getHeaderTableSize()); + HTTP2ServerSession session = new HTTP2ServerSession(endPoint, generator, listener, + new HTTP2FlowControl(getInitialWindowSize())); + + Parser parser = new ServerParser(connector.getByteBufferPool(), session); + HTTP2Connection connection = new HTTP2Connection(connector.getByteBufferPool(), connector.getExecutor(), + endPoint, parser, getInputBufferSize()); + + return configure(connection, connector, endPoint); + } + + protected abstract Session.Listener newSessionListener(Connector connector, EndPoint endPoint); +} diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index da0c5a081e6..57e80e86318 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -18,75 +18,35 @@ package org.eclipse.jetty.http2.server; -import org.eclipse.jetty.http2.HTTP2Connection; -import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; -import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.parser.Parser; -import org.eclipse.jetty.http2.parser.ServerParser; -import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.AbstractConnectionFactory; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class HTTP2ServerConnectionFactory extends AbstractConnectionFactory +public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionFactory { private static final Logger LOG = Log.getLogger(HTTP2ServerConnectionFactory.class); private static final String CHANNEL_ATTRIBUTE = HttpChannelOverHTTP2.class.getName(); private final HttpConfiguration httpConfiguration; - private int headerTableSize = 4096; - private int initialWindowSize = 65535; public HTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration) { - super("h2-12"); this.httpConfiguration = httpConfiguration; } - public int getHeaderTableSize() - { - return headerTableSize; - } - - public void setHeaderTableSize(int headerTableSize) - { - this.headerTableSize = headerTableSize; - } - - public int getInitialWindowSize() - { - return initialWindowSize; - } - - public void setInitialWindowSize(int initialWindowSize) - { - this.initialWindowSize = initialWindowSize; - } - @Override - public Connection newConnection(Connector connector, EndPoint endPoint) + protected Session.Listener newSessionListener(Connector connector, EndPoint endPoint) { - Session.Listener listener = new HTTPServerSessionListener(connector, httpConfiguration, endPoint); - - Generator generator = new Generator(connector.getByteBufferPool(), getHeaderTableSize()); - HTTP2ServerSession session = new HTTP2ServerSession(endPoint, generator, listener, new HTTP2FlowControl(), - getInitialWindowSize()); - - Parser parser = new ServerParser(connector.getByteBufferPool(), session); - HTTP2Connection connection = new HTTP2Connection(connector.getByteBufferPool(), connector.getExecutor(), - endPoint, parser, getInputBufferSize()); - - return configure(connection, connector, endPoint); + return new HTTPServerSessionListener(connector, httpConfiguration, endPoint); } private class HTTPServerSessionListener extends ServerSessionListener.Adapter implements Stream.Listener diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index 60fd4066a0e..9c34eced0c5 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -29,12 +29,13 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.Callback; public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Listener { - public HTTP2ServerSession(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int initialWindowSize) + public HTTP2ServerSession(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl) { - super(endPoint, generator, listener, flowControl, initialWindowSize, 2); + super(endPoint, generator, listener, flowControl, 2); } @Override @@ -43,7 +44,7 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis // SPEC: send a SETTINGS frame upon receiving the preface. HashMap settings = new HashMap<>(); settings.put(SettingsFrame.HEADER_TABLE_SIZE, getGenerator().getHeaderTableSize()); - settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialWindowSize()); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getFlowControl().getInitialWindowSize()); int maxConcurrentStreams = getMaxStreamCount(); if (maxConcurrentStreams >= 0) settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams); @@ -59,7 +60,7 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis if (stream != null) { stream.updateClose(frame.isEndStream(), false); - stream.process(frame); + stream.process(frame, Callback.Adapter.INSTANCE); Stream.Listener listener = notifyNewStream(stream, frame); stream.setListener(listener); // The listener may have sent a frame that closed the stream. diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java new file mode 100644 index 00000000000..3dbfd05e30c --- /dev/null +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java @@ -0,0 +1,39 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Connector; + +public class RawHTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionFactory +{ + private final Session.Listener listener; + + public RawHTTP2ServerConnectionFactory(Session.Listener listener) + { + this.listener = listener; + } + + @Override + protected Session.Listener newSessionListener(Connector connector, EndPoint endPoint) + { + return listener; + } +} diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 2a6940edb01..d172b194310 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -56,7 +56,6 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; import org.junit.After; import org.junit.Assert; import org.junit.Test; @@ -105,7 +104,8 @@ public class HTTP2ServerTest MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); - Generator.LeaseCallback lease = generator.generate(request, Callback.Adapter.INSTANCE); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generate(lease, request); // No preface bytes @@ -153,7 +153,8 @@ public class HTTP2ServerTest MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); - Generator.LeaseCallback lease = generator.generate(request, Callback.Adapter.INSTANCE); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generate(lease, request); lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); try (Socket client = new Socket(host, port)) @@ -215,7 +216,8 @@ public class HTTP2ServerTest MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); - Generator.LeaseCallback lease = generator.generate(request, Callback.Adapter.INSTANCE); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generate(lease, request); lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); try (Socket client = new Socket(host, port)) From b30152df27c334ccf15b6e83b72dd951742be398 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 14:08:56 +0200 Subject: [PATCH 069/269] Removed generation of padding bytes, which simplified the code a lot. Implemented slicing of flow controlled data to never exceed the flow control window. --- .../http2/client/HTTP2ClientSession.java | 2 +- .../jetty/http2/client/AbstractTest.java | 8 +- .../jetty/http2/client/FlowControlTest.java | 239 ++++++++---------- .../eclipse/jetty/http2/HTTP2Connection.java | 2 +- .../eclipse/jetty/http2/HTTP2FlowControl.java | 10 +- .../org/eclipse/jetty/http2/HTTP2Session.java | 167 ++++++------ .../org/eclipse/jetty/http2/HTTP2Stream.java | 10 +- .../org/eclipse/jetty/http2/ISession.java | 2 +- .../java/org/eclipse/jetty/http2/IStream.java | 2 +- .../api/server/ServerSessionListener.java | 10 + .../eclipse/jetty/http2/frames/DataFrame.java | 11 +- .../jetty/http2/generator/DataGenerator.java | 83 ++---- .../jetty/http2/generator/FrameGenerator.java | 9 +- .../jetty/http2/generator/Generator.java | 4 +- .../http2/generator/GoAwayGenerator.java | 2 +- .../http2/generator/HeadersGenerator.java | 32 +-- .../jetty/http2/generator/PingGenerator.java | 2 +- .../http2/generator/PriorityGenerator.java | 2 +- .../jetty/http2/generator/ResetGenerator.java | 2 +- .../http2/generator/SettingsGenerator.java | 2 +- .../generator/WindowUpdateGenerator.java | 2 +- .../jetty/http2/parser/DataBodyParser.java | 12 +- .../http2/frames/DataGenerateParseTest.java | 66 +---- .../AbstractHTTP2ServerConnectionFactory.java | 57 ++++- .../server/HTTP2ServerConnectionFactory.java | 18 +- .../http2/server/HTTP2ServerSession.java | 38 ++- .../RawHTTP2ServerConnectionFactory.java | 8 +- .../jetty/http2/server/HTTP2ServerTest.java | 6 +- 28 files changed, 392 insertions(+), 416 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index 7625dd748c8..1ddf8e09bb6 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -37,7 +37,7 @@ public class HTTP2ClientSession extends HTTP2Session public HTTP2ClientSession(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl) { - super(endPoint, generator, listener, flowControl, 1); + super(endPoint, generator, listener, flowControl, -1, 1); } @Override diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java index 8faf26193c7..54b7ce48cba 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -25,6 +25,7 @@ import javax.servlet.http.HttpServlet; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory; @@ -53,14 +54,17 @@ public class AbstractTest context.addServlet(new ServletHolder(servlet), path); prepareClient(); + server.start(); + client.start(); } - protected void startServer(Session.Listener listener) throws Exception + protected void startServer(ServerSessionListener listener) throws Exception { prepareServer(new RawHTTP2ServerConnectionFactory(listener)); prepareClient(); server.start(); + client.start(); } private void prepareServer(ConnectionFactory connectionFactory) @@ -77,7 +81,6 @@ public class AbstractTest QueuedThreadPool clientExecutor = new QueuedThreadPool(); clientExecutor.setName("client"); client = new HTTP2Client(clientExecutor); - server.addBean(client); } protected Session newClient(Session.Listener listener) throws Exception @@ -93,6 +96,7 @@ public class AbstractTest @After public void dispose() throws Exception { + client.stop(); server.stop(); } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index 327cdde1c89..7ea80ccc374 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -22,19 +22,23 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.Promise; import org.junit.Assert; import org.junit.Test; @@ -48,9 +52,11 @@ public class FlowControlTest extends AbstractTest // must stop sending data (although the initial window allows it). final int size = 512; - final CountDownLatch dataLatch = new CountDownLatch(1); + // We get 3 data frames: the first of 1024 and 2 of 512 each + // after the flow control window has been reduced. + final CountDownLatch dataLatch = new CountDownLatch(3); final AtomicReference callbackRef = new AtomicReference<>(); - startServer(new Session.Listener.Adapter() + startServer(new ServerSessionListener.Adapter() { @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) @@ -67,6 +73,7 @@ public class FlowControlTest extends AbstractTest @Override public void onData(Stream stream, DataFrame frame, Callback callback) { + dataLatch.countDown(); int dataFrameCount = dataFrames.incrementAndGet(); if (dataFrameCount == 1) { @@ -80,7 +87,6 @@ public class FlowControlTest extends AbstractTest { // Consume the data. callback.succeeded(); - dataLatch.countDown(); } } }; @@ -108,7 +114,7 @@ public class FlowControlTest extends AbstractTest settingsLatch.await(5, TimeUnit.SECONDS); // Send the second chunk of data, must not arrive since we're flow control stalled on the client. - stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(size * 2), false), Callback.Adapter.INSTANCE); + stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(size * 2), true), Callback.Adapter.INSTANCE); Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS)); // Consume the data arrived to server, this will resume flow control on the client. @@ -117,70 +123,67 @@ public class FlowControlTest extends AbstractTest Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); } -/* @Test public void testServerFlowControlOneBigWrite() throws Exception { final int windowSize = 1536; final int length = 5 * windowSize; final CountDownLatch settingsLatch = new CountDownLatch(1); - Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() + startServer(new ServerSessionListener.Adapter() { @Override - public void onSettings(Session session, SettingsInfo settingsInfo) + public void onSettings(Session session, SettingsFrame frame) { settingsLatch.countDown(); } @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) + public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter()); + MetaData.Response metaData = new MetaData.Response(200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + + DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(length), true); + stream.data(dataFrame, Callback.Adapter.INSTANCE); return null; } - }), null); + }); - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); - session.settings(new SettingsInfo(settings)); + Session session = newClient(new Session.Listener.Adapter()); + + Map settings = new HashMap<>(); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize); + session.settings(new SettingsFrame(settings, false), Callback.Adapter.INSTANCE); Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); - final Exchanger exchanger = new Exchanger<>(); - session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter() + final CountDownLatch dataLatch = new CountDownLatch(1); + final Exchanger exchanger = new Exchanger<>(); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter() { private AtomicInteger dataFrames = new AtomicInteger(); @Override - public void onData(Stream stream, DataInfo dataInfo) + public void onData(Stream stream, DataFrame frame, Callback callback) { try { int dataFrames = this.dataFrames.incrementAndGet(); - if (dataFrames == 1) + if (dataFrames == 1 || dataFrames == 2) { - // Do not consume nor read from the data frame. - // We should then be flow-control stalled - exchanger.exchange(dataInfo); + // Do not consume the data frame. + // We should then be flow-control stalled. + exchanger.exchange(callback); } - else if (dataFrames == 2) + else if (dataFrames == 3 || dataFrames == 4 || dataFrames == 5) { - // Read but not consume, we should be flow-control stalled - dataInfo.asByteBuffer(false); - exchanger.exchange(dataInfo); - } - else if (dataFrames == 3) - { - // Consume partially, we should be flow-control stalled - dataInfo.consumeInto(ByteBuffer.allocate(dataInfo.length() / 2)); - exchanger.exchange(dataInfo); - } - else if (dataFrames == 4 || dataFrames == 5) - { - // Consume totally - dataInfo.asByteBuffer(true); - exchanger.exchange(dataInfo); + // Consume totally. + callback.succeeded(); + if (frame.isEndStream()) + dataLatch.countDown(); } else { @@ -189,91 +192,83 @@ public class FlowControlTest extends AbstractTest } catch (InterruptedException x) { - throw new SPDYException(x); + callback.failed(x); } } }); - DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + Callback callback = exchanger.exchange(null, 5, TimeUnit.SECONDS); checkThatWeAreFlowControlStalled(exchanger); - Assert.assertEquals(windowSize, dataInfo.available()); - Assert.assertEquals(0, dataInfo.consumed()); - dataInfo.asByteBuffer(true); + // Consume the first chunk. + callback.succeeded(); - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + callback = exchanger.exchange(null, 5, TimeUnit.SECONDS); checkThatWeAreFlowControlStalled(exchanger); - Assert.assertEquals(0, dataInfo.available()); - Assert.assertEquals(0, dataInfo.consumed()); - dataInfo.consume(dataInfo.length()); + // Consume the second chunk. + callback.succeeded(); - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - checkThatWeAreFlowControlStalled(exchanger); + Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); + } - Assert.assertEquals(dataInfo.length() / 2, dataInfo.consumed()); - dataInfo.asByteBuffer(true); - - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); - // Check that we are not flow control stalled - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); + private void checkThatWeAreFlowControlStalled(Exchanger exchanger) throws Exception + { + try + { + exchanger.exchange(null, 1, TimeUnit.SECONDS); + } + catch (TimeoutException x) + { + // Expected. + } } @Test public void testClientFlowControlOneBigWrite() throws Exception { final int windowSize = 1536; - final Exchanger exchanger = new Exchanger<>(); + final Exchanger exchanger = new Exchanger<>(); final CountDownLatch settingsLatch = new CountDownLatch(1); - Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() + final CountDownLatch dataLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() { @Override - public void onConnect(Session session) + public Map onPreface(Session session) { - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); - session.settings(new SettingsInfo(settings), new FutureCallback()); + Map settings = new HashMap<>(); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize); + return settings; } @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) + public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - return new StreamFrameListener.Adapter() + MetaData.Response metaData = new MetaData.Response(200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + return new Stream.Listener.Adapter() { private AtomicInteger dataFrames = new AtomicInteger(); @Override - public void onData(Stream stream, DataInfo dataInfo) + public void onData(Stream stream, DataFrame frame, Callback callback) { try { int dataFrames = this.dataFrames.incrementAndGet(); - if (dataFrames == 1) + if (dataFrames == 1 || dataFrames == 2) { - // Do not consume nor read from the data frame. - // We should then be flow-control stalled - exchanger.exchange(dataInfo); + // Do not consume the data frame. + // We should then be flow-control stalled. + exchanger.exchange(callback); } - else if (dataFrames == 2) + else if (dataFrames == 3 || dataFrames == 4 || dataFrames == 5) { - // Read but not consume, we should be flow-control stalled - dataInfo.asByteBuffer(false); - exchanger.exchange(dataInfo); - } - else if (dataFrames == 3) - { - // Consume partially, we should be flow-control stalled - dataInfo.consumeInto(ByteBuffer.allocate(dataInfo.length() / 2)); - exchanger.exchange(dataInfo); - } - else if (dataFrames == 4 || dataFrames == 5) - { - // Consume totally - dataInfo.asByteBuffer(true); - exchanger.exchange(dataInfo); + // Consume totally. + callback.succeeded(); + if (frame.isEndStream()) + dataLatch.countDown(); } else { @@ -282,15 +277,17 @@ public class FlowControlTest extends AbstractTest } catch (InterruptedException x) { - throw new SPDYException(x); + callback.failed(x); } } }; } - }), new SessionFrameListener.Adapter() + }); + + Session session = newClient(new Session.Listener.Adapter() { @Override - public void onSettings(Session session, SettingsInfo settingsInfo) + public void onSettings(Session session, SettingsFrame frame) { settingsLatch.countDown(); } @@ -298,37 +295,34 @@ public class FlowControlTest extends AbstractTest Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); - Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, false); + FuturePromise streamPromise = new FuturePromise<>(); + session.newStream(requestFrame, streamPromise, null); + Stream stream = streamPromise.get(5, TimeUnit.SECONDS); + final int length = 5 * windowSize; - stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter()); + DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(length), true); + stream.data(dataFrame, Callback.Adapter.INSTANCE); - DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + Callback callback = exchanger.exchange(null, 5, TimeUnit.SECONDS); checkThatWeAreFlowControlStalled(exchanger); - Assert.assertEquals(windowSize, dataInfo.available()); - Assert.assertEquals(0, dataInfo.consumed()); - dataInfo.asByteBuffer(true); + // Consume the first chunk. + callback.succeeded(); - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); + callback = exchanger.exchange(null, 5, TimeUnit.SECONDS); checkThatWeAreFlowControlStalled(exchanger); - Assert.assertEquals(0, dataInfo.available()); - Assert.assertEquals(0, dataInfo.consumed()); - dataInfo.consume(dataInfo.length()); + // Consume the second chunk. + callback.succeeded(); - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - checkThatWeAreFlowControlStalled(exchanger); - - Assert.assertEquals(dataInfo.length() / 2, dataInfo.consumed()); - dataInfo.asByteBuffer(true); - - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); - // Check that we are not flow control stalled - dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS); - Assert.assertEquals(dataInfo.length(), dataInfo.consumed()); + Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); } + // TODO: add tests for session and stream flow control. + +/* @Test public void testStreamsStalledDoesNotStallOtherStreams() throws Exception { @@ -466,30 +460,5 @@ public class FlowControlTest extends AbstractTest assertThat("all data bytes have been received by the client", allDataReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); } - - private void checkThatWeAreFlowControlStalled(final Exchanger exchanger) - { - expectException(TimeoutException.class, new Callable() - { - @Override - public DataInfo call() throws Exception - { - return exchanger.exchange(null, 1, TimeUnit.SECONDS); - } - }); - } - - private void expectException(Class exception, Callable command) - { - try - { - command.call(); - Assert.fail(); - } - catch (Exception x) - { - Assert.assertSame(exception, x.getClass()); - } - } */ } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index c3243b86c19..a86e7e8b107 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -31,7 +31,7 @@ import org.eclipse.jetty.util.log.Logger; public class HTTP2Connection extends AbstractConnection { - private static final Logger LOG = Log.getLogger(HTTP2Connection.class); + protected static final Logger LOG = Log.getLogger(HTTP2Connection.class); private final ByteBufferPool byteBufferPool; private final Parser parser; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index 492c0679b2d..2dad4aae3ae 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -21,9 +21,13 @@ package org.eclipse.jetty.http2; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class HTTP2FlowControl implements FlowControl { + protected static final Logger LOG = Log.getLogger(HTTP2FlowControl.class); + private volatile int initialWindowSize; public HTTP2FlowControl(int initialWindowSize) @@ -86,6 +90,7 @@ public class HTTP2FlowControl implements FlowControl // We currently send a WindowUpdate every time, even if the frame was very small. // Other policies may send the WindowUpdate only upon reaching a threshold. + LOG.debug("Consumed {} on {}", length, stream); // Negative streamId allow for generation of bytes for both stream and session int streamId = stream != null ? -stream.getId() : 0; WindowUpdateFrame frame = new WindowUpdateFrame(streamId, length); @@ -95,7 +100,8 @@ public class HTTP2FlowControl implements FlowControl @Override public void onDataSent(ISession session, IStream stream, int length) { - stream.getSession().updateWindowSize(length); - stream.updateWindowSize(length); + session.updateWindowSize(length); + if (stream != null) + stream.updateWindowSize(length); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 7295cfd18f5..6136aa1b92f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -24,11 +24,10 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; @@ -83,14 +82,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final Flusher flusher; private volatile int maxStreamCount; - public HTTP2Session(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int initialStreamId) + public HTTP2Session(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int maxStreams, int initialStreamId) { this.endPoint = endPoint; this.generator = generator; this.listener = listener; this.flowControl = flowControl; this.flusher = new Flusher(4); - this.maxStreamCount = -1; + this.maxStreamCount = maxStreams; this.streamIds.set(initialStreamId); this.windowSize.set(flowControl.getInitialWindowSize()); } @@ -125,7 +124,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener public void succeeded() { int consumed = frame.getFlowControlledLength(); - LOG.debug("Flow control: {} consumed on {}", consumed, stream); flowControl.onDataConsumed(HTTP2Session.this, stream, consumed); } }); @@ -185,7 +183,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (LOG.isDebugEnabled()) { String reason = tryConvertPayload(frame.getPayload()); - LOG.debug("Received {}: {}/{}", frame.getType(), frame.getError(), reason); + LOG.debug("Received {}: {}/'{}'", frame.getType(), frame.getError(), reason); } flusher.close(); @@ -250,7 +248,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener stream.setListener(listener); FlusherEntry entry = new FlusherEntry(stream, frame, new PromiseCallback<>(promise, stream)); - flusher.offer(entry); + flusher.append(entry); } // Iterate outside the synchronized block. flusher.iterate(); @@ -286,13 +284,11 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void frame(IStream stream, Frame frame, Callback callback) { - int flowControlledLength = frame.getFlowControlledLength(); - if (flowControlledLength > 0) - callback = new FlowControlCallback(stream, flowControlledLength, callback); // We want to generate as late as possible to allow re-prioritization. FlusherEntry entry = new FlusherEntry(stream, frame, callback); LOG.debug("Sending {}", frame); - flusher.flush(entry); + flusher.append(entry); + flusher.iterate(); } protected void disconnect() @@ -390,11 +386,13 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } @Override - public int updateWindowSize(int delta) + public void updateWindowSize(int delta) { - int oldSize = windowSize.getAndAdd(delta); - LOG.debug("Flow control: updated window {} -> {} for {}", oldSize, oldSize + delta, this); - return oldSize; + if (delta != 0) + { + int oldSize = windowSize.getAndAdd(delta); + HTTP2FlowControl.LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize + delta, this); + } } private void updateLastStreamId(int streamId) @@ -437,20 +435,20 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private class Flusher extends IteratingCallback { private final ArrayQueue queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH); - private final Set stalled = new HashSet<>(); + private final Map streams = new HashMap<>(); private final List reset = new ArrayList<>(); private final ByteBufferPool.Lease lease = new ByteBufferPool.Lease(generator.getByteBufferPool()); private final int maxGather; private final List active; private boolean closed; - public Flusher(int maxGather) + private Flusher(int maxGather) { this.maxGather = maxGather; this.active = new ArrayList<>(maxGather); } - private void offer(FlusherEntry entry) + private void append(FlusherEntry entry) { boolean fail = false; synchronized (queue) @@ -464,7 +462,21 @@ public abstract class HTTP2Session implements ISession, Parser.Listener closed(entry); } - public int getQueueSize() + private void prepend(FlusherEntry entry) + { + boolean fail = false; + synchronized (queue) + { + if (closed) + fail = true; + else + queue.add(0, entry); + } + if (fail) + closed(entry); + } + + private int getQueueSize() { synchronized (queue) { @@ -472,12 +484,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } - private void flush(FlusherEntry entry) - { - offer(entry); - iterate(); - } - @Override protected Action process() throws Exception { @@ -486,19 +492,20 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (closed) return Action.IDLE; + int sessionWindow = getWindowSize(); int nonStalledIndex = 0; int size = queue.size(); while (nonStalledIndex < size) { FlusherEntry entry = queue.get(nonStalledIndex); - IStream stream = entry.getStream(); - boolean flowControlled = entry.getFrame().getFlowControlledLength() > 0; - if (flowControlled) + IStream stream = entry.stream; + int frameWindow = entry.frame.getFlowControlledLength(); + if (frameWindow > 0) { // Is the session stalled ? - if (getWindowSize() <= 0) + if (sessionWindow <= 0) { - LOG.debug("Flow control: session stalled {}", HTTP2Session.this); + HTTP2FlowControl.LOG.debug("Session stalled {}", HTTP2Session.this); ++nonStalledIndex; // There may be *non* flow controlled frames to send. continue; @@ -506,18 +513,17 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (stream != null) { - // Is it a frame belonging to an already stalled stream ? - if (stalled.contains(stream)) + Integer streamWindow = streams.get(stream); + if (streamWindow == null) { - ++nonStalledIndex; - continue; + streamWindow = stream.getWindowSize(); + streams.put(stream, streamWindow); } - // Is the stream stalled ? - if (stream.getWindowSize() <= 0) + // Is it a frame belonging to an already stalled stream ? + if (streamWindow <= 0) { - LOG.debug("Flow control: stream stalled {}", stream); - stalled.add(stream); + HTTP2FlowControl.LOG.debug("Stream stalled {}", stream); ++nonStalledIndex; continue; } @@ -528,18 +534,23 @@ public abstract class HTTP2Session implements ISession, Parser.Listener queue.remove(nonStalledIndex); --size; - // Has the stream been reset ? - if (stream != null && stream.isReset() && flowControlled) + // If the stream has been reset, don't send flow controlled frames. + if (stream != null && stream.isReset() && frameWindow > 0) { reset.add(entry); continue; } + // Reduce the flow control windows. + sessionWindow -= frameWindow; + if (stream != null && frameWindow > 0) + streams.put(stream, streams.get(stream) - frameWindow); + active.add(entry); if (active.size() == maxGather) break; } - stalled.clear(); + streams.clear(); } for (int i = 0; i < reset.size(); ++i) @@ -556,7 +567,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener for (int i = 0; i < active.size(); ++i) { FlusherEntry entry = active.get(i); - generator.generate(lease, entry.getFrame()); + entry.generate(lease); } List byteBuffers = lease.getByteBuffers(); @@ -580,6 +591,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void failed(Throwable x) { + LOG.debug(x); lease.recycle(); for (int i = 0; i < active.size(); ++i) { @@ -625,6 +637,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final IStream stream; private final Frame frame; private final Callback callback; + private int length; private FlusherEntry(IStream stream, Frame frame, Callback callback) { @@ -633,20 +646,45 @@ public abstract class HTTP2Session implements ISession, Parser.Listener this.callback = callback; } - public IStream getStream() + public void generate(ByteBufferPool.Lease lease) { - return stream; - } + try + { + int windowSize = stream == null ? getWindowSize() : stream.getWindowSize(); + int frameLength = frame.getFlowControlledLength(); + if (frameLength > 0) + this.length = Math.min(frameLength, windowSize); - public Frame getFrame() - { - return frame; + generator.generate(lease, frame, windowSize); + LOG.debug("Generated {}, windowSize={}", frame, windowSize); + } + catch (Throwable x) + { + LOG.debug("Frame generation failure", x); + failed(x); + } } @Override public void succeeded() { - callback.succeeded(); + flowControl.onDataSent(HTTP2Session.this, stream, -length); + // Do we have more to send ? + if (frame.getFlowControlledLength() > 0) + { + // We have written part of the frame, but there is more to write. + // We need to keep the correct ordering of frames, to avoid that other + // frames for the same stream are written before this one is finished. + flusher.prepend(this); + } + else + { + callback.succeeded(); + // TODO: what below is needed ? YES IT IS. +// stream.updateCloseState(dataInfo.isClose(), true); +// if (stream.isClosed()) +// removeStream(stream); + } } @Override @@ -656,12 +694,12 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } - public class PromiseCallback implements Callback + private class PromiseCallback implements Callback { private final Promise promise; private final C value; - public PromiseCallback(Promise promise, C value) + private PromiseCallback(Promise promise, C value) { this.promise = promise; this.value = value; @@ -679,31 +717,4 @@ public abstract class HTTP2Session implements ISession, Parser.Listener promise.failed(x); } } - - private class FlowControlCallback implements Callback - { - private final IStream stream; - private final int length; - private final Callback callback; - - private FlowControlCallback(IStream stream, int length, Callback callback) - { - this.stream = stream; - this.length = length; - this.callback = callback; - } - - @Override - public void succeeded() - { - flowControl.onDataSent(HTTP2Session.this, stream, -length); - callback.succeeded(); - } - - @Override - public void failed(Throwable x) - { - callback.failed(x); - } - } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index a0a8e79752f..880c1eeddf8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -205,11 +205,13 @@ public class HTTP2Stream implements IStream } @Override - public int updateWindowSize(int delta) + public void updateWindowSize(int delta) { - int oldSize = windowSize.getAndAdd(delta); - LOG.debug("Flow control: updated window {} -> {} for {}", oldSize, oldSize + delta, this); - return oldSize; + if (delta != 0) + { + int oldSize = windowSize.getAndAdd(delta); + HTTP2FlowControl.LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize + delta, this); + } } protected boolean notifyData(DataFrame frame, Callback callback) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index 916dddc6cca..af08c4c3464 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -29,5 +29,5 @@ public interface ISession extends Session public void frame(IStream stream, Frame frame, Callback callback); - public int updateWindowSize(int delta); + public void updateWindowSize(int delta); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 5bd23056bb6..05281dad2a8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -46,5 +46,5 @@ public interface IStream extends Stream public int getWindowSize(); - public int updateWindowSize(int delta); + public void updateWindowSize(int delta); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java index 3eb90e8867b..dc1ce9152c6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java @@ -18,17 +18,27 @@ package org.eclipse.jetty.http2.api.server; +import java.util.Map; + import org.eclipse.jetty.http2.api.Session; public interface ServerSessionListener extends Session.Listener { public void onConnect(Session session); + public Map onPreface(Session session); + public static class Adapter extends Session.Listener.Adapter implements ServerSessionListener { @Override public void onConnect(Session session) { } + + @Override + public Map onPreface(Session session) + { + return null; + } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java index 3bc7ac73814..73518b8f8ea 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -25,20 +25,13 @@ public class DataFrame extends Frame private final int streamId; private final ByteBuffer data; private final boolean endStream; - private final int length; public DataFrame(int streamId, ByteBuffer data, boolean endStream) - { - this(streamId, data, endStream, 0); - } - - public DataFrame(int streamId, ByteBuffer data, boolean endStream, int padding) { super(FrameType.DATA); this.streamId = streamId; this.data = data; this.endStream = endStream; - this.length = data.remaining() + padding; } public int getStreamId() @@ -59,12 +52,12 @@ public class DataFrame extends Frame @Override public int getFlowControlledLength() { - return length; + return data.remaining(); } @Override public String toString() { - return String.format("%s{length:%d/%d}", super.toString(), data.remaining(), length); + return String.format("%s{length:%d,end=%b}", super.toString(), data.remaining(), endStream); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index d7f74ff2922..465ddc6df35 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -35,85 +35,58 @@ public class DataGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { DataFrame dataFrame = (DataFrame)frame; - generateData(lease, dataFrame.getStreamId(), dataFrame.getData(), dataFrame.isEndStream(), false, null); + generateData(lease, dataFrame.getStreamId(), dataFrame.getData(), dataFrame.isEndStream(), maxLength); } - public void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, boolean compress, byte[] paddingBytes) + public void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, int maxLength) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); - int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; - // Leave space for at least one byte of content. - if (paddingLength > Frame.MAX_LENGTH - 3) - throw new IllegalArgumentException("Invalid padding length: " + paddingLength); - if (compress) - throw new IllegalArgumentException("Data compression not supported"); - - int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; int dataLength = data.remaining(); + if (dataLength <= maxLength && dataLength <= Frame.MAX_LENGTH) + { + // Single frame. + generateFrame(lease, streamId, data, last); + return; + } - // Can we fit just one frame ? - if (dataLength + extraPaddingBytes + paddingLength <= Frame.MAX_LENGTH) + // Other cases, we need to slice the original buffer into multiple frames. + + int length = Math.min(maxLength, dataLength); + int dataBytesPerFrame = Frame.MAX_LENGTH; + int frames = length / dataBytesPerFrame; + if (frames * dataBytesPerFrame != length) + ++frames; + + int begin = data.position(); + int end = data.limit(); + for (int i = 1; i <= frames; ++i) { - generateData(lease, streamId, data, last, compress, extraPaddingBytes, paddingBytes); - } - else - { - int dataBytesPerFrame = Frame.MAX_LENGTH - extraPaddingBytes - paddingLength; - int frames = dataLength / dataBytesPerFrame; - if (frames * dataBytesPerFrame != dataLength) - { - ++frames; - } - int limit = data.limit(); - for (int i = 1; i <= frames; ++i) - { - data.limit(Math.min(dataBytesPerFrame * i, limit)); - ByteBuffer slice = data.slice(); - data.position(data.limit()); - generateData(lease, streamId, slice, i == frames && last, compress, extraPaddingBytes, paddingBytes); - } + data.limit(begin + Math.min(dataBytesPerFrame * i, length)); + ByteBuffer slice = data.slice(); + data.position(data.limit()); + generateFrame(lease, streamId, slice, i == frames && last); } + data.limit(end); } - private void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, boolean compress, int extraPaddingBytes, byte[] paddingBytes) + private void generateFrame(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last) { - int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; - int length = extraPaddingBytes + data.remaining() + paddingLength; + int length = data.remaining(); int flags = Flag.NONE; if (last) flags |= Flag.END_STREAM; - if (extraPaddingBytes > 0) - flags |= Flag.PADDING_LOW; - if (extraPaddingBytes > 1) - flags |= Flag.PADDING_HIGH; - if (compress) - flags |= Flag.COMPRESS; - ByteBuffer header = generateHeader(lease, FrameType.DATA, Frame.HEADER_LENGTH + extraPaddingBytes, length, flags, streamId); - - if (extraPaddingBytes == 2) - { - header.putShort((short)paddingLength); - } - else if (extraPaddingBytes == 1) - { - header.put((byte)paddingLength); - } + ByteBuffer header = generateHeader(lease, FrameType.DATA, length, flags, streamId); BufferUtil.flipToFlush(header, 0); lease.append(header, true); lease.append(data, false); - - if (paddingBytes != null) - { - lease.append(ByteBuffer.wrap(paddingBytes), false); - } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java index ae345710c23..cc2bdb0e752 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java @@ -33,15 +33,10 @@ public abstract class FrameGenerator this.headerGenerator = headerGenerator; } - public abstract void generate(ByteBufferPool.Lease lease, Frame frame); + public abstract void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength); protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int length, int flags, int streamId) { - return generateHeader(lease, frameType, Frame.HEADER_LENGTH + length, length, flags, streamId); - } - - protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int capacity, int length, int flags, int streamId) - { - return headerGenerator.generate(lease, frameType, capacity, length, flags, streamId); + return headerGenerator.generate(lease, frameType, Frame.HEADER_LENGTH + length, length, flags, streamId); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 61c85d4fe96..f33c3fab884 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -68,8 +68,8 @@ public class Generator return headerTableSize; } - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { - generators[frame.getType().getType()].generate(lease, frame); + generators[frame.getType().getType()].generate(lease, frame, maxLength); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index 121059875f0..e3a2b1afc03 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -35,7 +35,7 @@ public class GoAwayGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { GoAwayFrame goAwayFrame = (GoAwayFrame)frame; generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index e8e19a6be0c..1d4dc73e68b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -40,52 +40,30 @@ public class HeadersGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { HeadersFrame headersFrame = (HeadersFrame)frame; - generate(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream(), null); + generate(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream()); } - private void generate(ByteBufferPool.Lease lease, int streamId, MetaData metaData, boolean contentFollows, byte[] paddingBytes) + private void generate(ByteBufferPool.Lease lease, int streamId, MetaData metaData, boolean contentFollows) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); - int paddingLength = paddingBytes == null ? 0 : paddingBytes.length; - // Leave space for at least one byte of content. - if (paddingLength > Frame.MAX_LENGTH - 3) - throw new IllegalArgumentException("Invalid padding length: " + paddingLength); - - int extraPaddingBytes = paddingLength > 0xFF ? 2 : paddingLength > 0 ? 1 : 0; encoder.encode(metaData, lease); - long hpackLength = lease.getTotalLength(); - - long length = extraPaddingBytes + hpackLength + paddingLength; + long length = lease.getTotalLength(); if (length > Frame.MAX_LENGTH) throw new IllegalArgumentException("Invalid headers, too big"); int flags = Flag.END_HEADERS; if (!contentFollows) flags |= Flag.END_STREAM; - if (extraPaddingBytes > 0) - flags |= Flag.PADDING_LOW; - if (extraPaddingBytes > 1) - flags |= Flag.PADDING_HIGH; - ByteBuffer header = generateHeader(lease, FrameType.HEADERS, Frame.HEADER_LENGTH + extraPaddingBytes, (int)length, flags, streamId); - - if (extraPaddingBytes == 2) - header.putShort((short)paddingLength); - else if (extraPaddingBytes == 1) - header.put((byte)paddingLength); + ByteBuffer header = generateHeader(lease, FrameType.HEADERS, (int)length, flags, streamId); BufferUtil.flipToFlush(header, 0); lease.prepend(header, true); - - if (paddingBytes != null) - { - lease.append(ByteBuffer.wrap(paddingBytes), false); - } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java index ec5db1a151a..d3ce03cb735 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java @@ -35,7 +35,7 @@ public class PingGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { PingFrame pingFrame = (PingFrame)frame; generatePing(lease, pingFrame.getPayload(), pingFrame.isReply()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java index 4ebb52d715f..6faef2d664c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java @@ -35,7 +35,7 @@ public class PriorityGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { PriorityFrame priorityFrame = (PriorityFrame)frame; generatePriority(lease, priorityFrame.getStreamId(), priorityFrame.getDependentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java index 781f29346d0..3cf0455d31a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java @@ -35,7 +35,7 @@ public class ResetGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { ResetFrame resetFrame = (ResetFrame)frame; generateReset(lease, resetFrame.getStreamId(), resetFrame.getError()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index 43971341750..a53d59b5e21 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -36,7 +36,7 @@ public class SettingsGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { SettingsFrame settingsFrame = (SettingsFrame)frame; generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java index e9be713989e..f3eaa438a6c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java @@ -35,7 +35,7 @@ public class WindowUpdateGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { WindowUpdateFrame windowUpdateFrame = (WindowUpdateFrame)frame; generateWindowUpdate(lease, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index 4992f416103..3a2e111e0e8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -49,7 +49,7 @@ public class DataBodyParser extends BodyParser notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame"); return false; } - return onData(BufferUtil.EMPTY_BUFFER, false, 0); + return onData(BufferUtil.EMPTY_BUFFER, false); } @Override @@ -112,11 +112,11 @@ public class DataBodyParser extends BodyParser buffer.position(position + size); length -= size; - loop = paddingLength == 0; if (length == 0) { state = State.PADDING; - if (onData(slice, false, paddingLength)) + loop = paddingLength == 0; + if (onData(slice, false)) { return Result.ASYNC; } @@ -125,7 +125,7 @@ public class DataBodyParser extends BodyParser { // TODO: check the semantic of Flag.END_SEGMENT. // We got partial data, simulate a smaller frame, and stay in DATA state. - if (onData(slice, true, 0)) + if (onData(slice, true)) { return Result.ASYNC; } @@ -153,9 +153,9 @@ public class DataBodyParser extends BodyParser return Result.PENDING; } - private boolean onData(ByteBuffer buffer, boolean fragment, int padding) + private boolean onData(ByteBuffer buffer, boolean fragment) { - DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding); + DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream()); return notifyData(frame); } diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 23c1981eff0..3e77b30991c 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -48,47 +48,18 @@ public class DataGenerateParseTest @Test public void testGenerateParseNoContentNoPadding() { - testGenerateParseContent(0, BufferUtil.EMPTY_BUFFER); - } - - @Test - public void testGenerateParseNoContentSmallPadding() - { - testGenerateParseContent(128, BufferUtil.EMPTY_BUFFER); - } - - @Test - public void testGenerateParseNoContentLargePadding() - { - testGenerateParseContent(1024, BufferUtil.EMPTY_BUFFER); + testGenerateParseContent(BufferUtil.EMPTY_BUFFER); } @Test public void testGenerateParseSmallContentNoPadding() { - testGenerateParseSmallContent(0); + testGenerateParseContent(ByteBuffer.wrap(smallContent)); } - @Test - public void testGenerateParseSmallContentSmallPadding() + private void testGenerateParseContent(ByteBuffer content) { - testGenerateParseSmallContent(128); - } - - @Test - public void testGenerateParseSmallContentLargePadding() - { - testGenerateParseSmallContent(1024); - } - - private void testGenerateParseSmallContent(int paddingLength) - { - testGenerateParseContent(paddingLength, ByteBuffer.wrap(smallContent)); - } - - private void testGenerateParseContent(int paddingLength, ByteBuffer content) - { - List frames = testGenerateParse(paddingLength, content); + List frames = testGenerateParse(content); Assert.assertEquals(1, frames.size()); DataFrame frame = frames.get(0); Assert.assertTrue(frame.getStreamId() != 0); @@ -98,26 +69,9 @@ public class DataGenerateParseTest @Test public void testGenerateParseLargeContent() - { - testGenerateParseLargeContent(0); - } - - @Test - public void testGenerateParseLargeContentSmallPadding() - { - testGenerateParseLargeContent(128); - } - - @Test - public void testGenerateParseLargeContentLargePadding() - { - testGenerateParseLargeContent(1024); - } - - private void testGenerateParseLargeContent(int paddingLength) { ByteBuffer content = ByteBuffer.wrap(largeContent); - List frames = testGenerateParse(paddingLength, content); + List frames = testGenerateParse(content); Assert.assertEquals(9, frames.size()); ByteBuffer aggregate = ByteBuffer.allocate(content.remaining()); for (int i = 1; i <= frames.size(); ++i) @@ -131,7 +85,7 @@ public class DataGenerateParseTest Assert.assertEquals(content, aggregate); } - private List testGenerateParse(int paddingLength, ByteBuffer... data) + private List testGenerateParse(ByteBuffer data) { DataGenerator generator = new DataGenerator(new HeaderGenerator()); @@ -140,10 +94,7 @@ public class DataGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - for (int j = 1; j <= data.length; ++j) - { - generator.generateData(lease, 13, data[j - 1].slice(), j == data.length, false, new byte[paddingLength]); - } + generator.generateData(lease, 13, data.slice(), true, data.remaining()); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @@ -171,7 +122,8 @@ public class DataGenerateParseTest DataGenerator generator = new DataGenerator(new HeaderGenerator()); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateData(lease, 13, ByteBuffer.wrap(largeContent).slice(), true, false, new byte[1024]); + ByteBuffer data = ByteBuffer.wrap(largeContent); + generator.generateData(lease, 13, data.slice(), true, data.remaining()); final List frames = new ArrayList<>(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 4999a81be8c..77ae91d6264 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -18,12 +18,16 @@ package org.eclipse.jetty.http2.server; +import java.util.concurrent.Executor; + import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.ServerParser; +import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.AbstractConnectionFactory; @@ -33,6 +37,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne { private int headerTableSize = 4096; private int initialWindowSize = 65535; + private int maxConcurrentStreams = -1; public AbstractHTTP2ServerConnectionFactory() { @@ -59,21 +64,63 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne this.initialWindowSize = initialWindowSize; } + public int getMaxConcurrentStreams() + { + return maxConcurrentStreams; + } + + public void setMaxConcurrentStreams(int maxConcurrentStreams) + { + this.maxConcurrentStreams = maxConcurrentStreams; + } + @Override public Connection newConnection(Connector connector, EndPoint endPoint) { - Session.Listener listener = newSessionListener(connector, endPoint); + ServerSessionListener listener = newSessionListener(connector, endPoint); Generator generator = new Generator(connector.getByteBufferPool(), getHeaderTableSize()); HTTP2ServerSession session = new HTTP2ServerSession(endPoint, generator, listener, - new HTTP2FlowControl(getInitialWindowSize())); + new HTTP2FlowControl(getInitialWindowSize()), getMaxConcurrentStreams()); Parser parser = new ServerParser(connector.getByteBufferPool(), session); - HTTP2Connection connection = new HTTP2Connection(connector.getByteBufferPool(), connector.getExecutor(), - endPoint, parser, getInputBufferSize()); + HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(), + endPoint, parser, getInputBufferSize(), listener, session); return configure(connection, connector, endPoint); } - protected abstract Session.Listener newSessionListener(Connector connector, EndPoint endPoint); + protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint); + + private class HTTP2ServerConnection extends HTTP2Connection + { + private final ServerSessionListener listener; + private final Session session; + + public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, int inputBufferSize, ServerSessionListener listener, Session session) + { + super(byteBufferPool, executor, endPoint, parser, inputBufferSize); + this.listener = listener; + this.session = session; + } + + @Override + public void onOpen() + { + super.onOpen(); + notifyConnect(session); + } + + private void notifyConnect(Session session) + { + try + { + listener.onConnect(session); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } + } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 57e80e86318..37307839e9f 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -18,12 +18,16 @@ package org.eclipse.jetty.http2.server; +import java.util.HashMap; +import java.util.Map; + import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; @@ -44,7 +48,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF } @Override - protected Session.Listener newSessionListener(Connector connector, EndPoint endPoint) + protected ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint) { return new HTTPServerSessionListener(connector, httpConfiguration, endPoint); } @@ -62,6 +66,18 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF this.endPoint = endPoint; } + @Override + public Map onPreface(Session session) + { + Map settings = new HashMap<>(); + settings.put(SettingsFrame.HEADER_TABLE_SIZE, getHeaderTableSize()); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialWindowSize()); + int maxConcurrentStreams = getMaxConcurrentStreams(); + if (maxConcurrentStreams >= 0) + settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams); + return settings; + } + @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index 9c34eced0c5..e721da5e44a 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -18,36 +18,43 @@ package org.eclipse.jetty.http2.server; -import java.util.HashMap; +import java.util.Collections; +import java.util.Map; import org.eclipse.jetty.http2.FlowControl; import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.IStream; +import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Listener { - public HTTP2ServerSession(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl) + private static final Logger LOG = Log.getLogger(HTTP2ServerSession.class); + + private final ServerSessionListener listener; + + public HTTP2ServerSession(EndPoint endPoint, Generator generator, ServerSessionListener listener, FlowControl flowControl, int maxStreams) { - super(endPoint, generator, listener, flowControl, 2); + super(endPoint, generator, listener, flowControl, maxStreams, 2); + this.listener = listener; } @Override public boolean onPreface() { // SPEC: send a SETTINGS frame upon receiving the preface. - HashMap settings = new HashMap<>(); - settings.put(SettingsFrame.HEADER_TABLE_SIZE, getGenerator().getHeaderTableSize()); - settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getFlowControl().getInitialWindowSize()); - int maxConcurrentStreams = getMaxStreamCount(); - if (maxConcurrentStreams >= 0) - settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams); + Map settings = notifyPreface(this); + if (settings == null) + settings = Collections.emptyMap(); SettingsFrame frame = new SettingsFrame(settings, false); settings(frame, disconnectCallback); return false; @@ -69,4 +76,17 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis } return false; } + + private Map notifyPreface(Session session) + { + try + { + return listener.onPreface(session); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return null; + } + } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java index 3dbfd05e30c..ddf3d635009 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java @@ -18,21 +18,21 @@ package org.eclipse.jetty.http2.server; -import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; public class RawHTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionFactory { - private final Session.Listener listener; + private final ServerSessionListener listener; - public RawHTTP2ServerConnectionFactory(Session.Listener listener) + public RawHTTP2ServerConnectionFactory(ServerSessionListener listener) { this.listener = listener; } @Override - protected Session.Listener newSessionListener(Connector connector, EndPoint endPoint) + protected ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint) { return listener; } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index d172b194310..c6845462b38 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -105,7 +105,7 @@ public class HTTP2ServerTest host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generate(lease, request); + generator.generate(lease, request, 0); // No preface bytes @@ -154,7 +154,7 @@ public class HTTP2ServerTest host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generate(lease, request); + generator.generate(lease, request, 0); lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); try (Socket client = new Socket(host, port)) @@ -217,7 +217,7 @@ public class HTTP2ServerTest host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generate(lease, request); + generator.generate(lease, request, 0); lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); try (Socket client = new Socket(host, port)) From fb93973c9d799829b2ecb9d792fe3f8594c906db Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 15:22:03 +0200 Subject: [PATCH 070/269] Improved flow control logging. --- .../org/eclipse/jetty/http2/FlowControl.java | 4 ++ .../eclipse/jetty/http2/HTTP2FlowControl.java | 45 +++++++++++++++---- .../org/eclipse/jetty/http2/HTTP2Session.java | 14 +++--- .../org/eclipse/jetty/http2/HTTP2Stream.java | 8 +--- .../org/eclipse/jetty/http2/ISession.java | 2 +- .../java/org/eclipse/jetty/http2/IStream.java | 2 +- 6 files changed, 50 insertions(+), 25 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java index 44b29c358b0..40618addffd 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java @@ -35,4 +35,8 @@ public interface FlowControl public void onDataConsumed(ISession session, IStream stream, int length); public void onDataSent(ISession session, IStream stream, int length); + + public void onSessionStalled(ISession session); + + public void onStreamStalled(IStream stream); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index 2dad4aae3ae..8b0cf817fb7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -26,7 +26,7 @@ import org.eclipse.jetty.util.log.Logger; public class HTTP2FlowControl implements FlowControl { - protected static final Logger LOG = Log.getLogger(HTTP2FlowControl.class); + private static final Logger LOG = Log.getLogger(HTTP2FlowControl.class); private volatile int initialWindowSize; @@ -56,24 +56,33 @@ public class HTTP2FlowControl implements FlowControl int delta = initialWindowSize - windowSize; // Update the sessions's window size. - session.updateWindowSize(delta); + int oldSize = session.updateWindowSize(delta); + LOG.debug("Updated session initial window {} -> {} for {}", oldSize, oldSize + delta, session); // Update the streams' window size. for (Stream stream : session.getStreams()) - ((IStream)stream).updateWindowSize(delta); + { + oldSize = ((IStream)stream).updateWindowSize(delta); + LOG.debug("Updated stream initial window {} -> {} for {}", oldSize, oldSize + delta, stream); + } } @Override public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame) { + int delta = frame.getWindowDelta(); if (frame.getStreamId() > 0) { if (stream != null) - stream.updateWindowSize(frame.getWindowDelta()); + { + int oldSize = stream.updateWindowSize(delta); + LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize + delta, stream); + } } else { - session.updateWindowSize(frame.getWindowDelta()); + int oldSize = session.updateWindowSize(frame.getWindowDelta()); + LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize + delta, session); } } @@ -90,7 +99,7 @@ public class HTTP2FlowControl implements FlowControl // We currently send a WindowUpdate every time, even if the frame was very small. // Other policies may send the WindowUpdate only upon reaching a threshold. - LOG.debug("Consumed {} on {}", length, stream); + LOG.debug("Data consumed, increasing window by {} for {}", length, stream); // Negative streamId allow for generation of bytes for both stream and session int streamId = stream != null ? -stream.getId() : 0; WindowUpdateFrame frame = new WindowUpdateFrame(streamId, length); @@ -100,8 +109,28 @@ public class HTTP2FlowControl implements FlowControl @Override public void onDataSent(ISession session, IStream stream, int length) { - session.updateWindowSize(length); + if (length == 0) + return; + + LOG.debug("Data sent, decreasing window by {}", length); + int oldSize = session.updateWindowSize(-length); + LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize - length, session); if (stream != null) - stream.updateWindowSize(length); + { + oldSize = stream.updateWindowSize(-length); + LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize - length, stream); + } + } + + @Override + public void onSessionStalled(ISession session) + { + LOG.debug("Session stalled {}", session); + } + + @Override + public void onStreamStalled(IStream stream) + { + LOG.debug("Stream stalled {}", stream); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 6136aa1b92f..3025c2ebf8c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -386,13 +386,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } @Override - public void updateWindowSize(int delta) + public int updateWindowSize(int delta) { - if (delta != 0) - { - int oldSize = windowSize.getAndAdd(delta); - HTTP2FlowControl.LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize + delta, this); - } + return windowSize.getAndAdd(delta); } private void updateLastStreamId(int streamId) @@ -505,7 +501,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener // Is the session stalled ? if (sessionWindow <= 0) { - HTTP2FlowControl.LOG.debug("Session stalled {}", HTTP2Session.this); + flowControl.onSessionStalled(HTTP2Session.this); ++nonStalledIndex; // There may be *non* flow controlled frames to send. continue; @@ -523,7 +519,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener // Is it a frame belonging to an already stalled stream ? if (streamWindow <= 0) { - HTTP2FlowControl.LOG.debug("Stream stalled {}", stream); + flowControl.onStreamStalled(stream); ++nonStalledIndex; continue; } @@ -668,7 +664,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void succeeded() { - flowControl.onDataSent(HTTP2Session.this, stream, -length); + flowControl.onDataSent(HTTP2Session.this, stream, length); // Do we have more to send ? if (frame.getFlowControlledLength() > 0) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 880c1eeddf8..41e176dd2f4 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -205,13 +205,9 @@ public class HTTP2Stream implements IStream } @Override - public void updateWindowSize(int delta) + public int updateWindowSize(int delta) { - if (delta != 0) - { - int oldSize = windowSize.getAndAdd(delta); - HTTP2FlowControl.LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize + delta, this); - } + return windowSize.getAndAdd(delta); } protected boolean notifyData(DataFrame frame, Callback callback) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index af08c4c3464..916dddc6cca 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -29,5 +29,5 @@ public interface ISession extends Session public void frame(IStream stream, Frame frame, Callback callback); - public void updateWindowSize(int delta); + public int updateWindowSize(int delta); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 05281dad2a8..5bd23056bb6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -46,5 +46,5 @@ public interface IStream extends Stream public int getWindowSize(); - public void updateWindowSize(int delta); + public int updateWindowSize(int delta); } From 388262227e42bb77a494485be9689affd7f1a399 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 16:28:54 +0200 Subject: [PATCH 071/269] Split the generation of frames into 2: flow-controlled and non-flow-controlled. This gives better code separation and proper removal of streams when flow controlled frames complete. --- .../jetty/http2/client/FlowControlTest.java | 8 + .../eclipse/jetty/http2/HTTP2FlowControl.java | 2 +- .../org/eclipse/jetty/http2/HTTP2Session.java | 155 +++++++++++------- .../org/eclipse/jetty/http2/HTTP2Stream.java | 4 +- .../org/eclipse/jetty/http2/ISession.java | 5 +- .../eclipse/jetty/http2/frames/DataFrame.java | 3 +- .../org/eclipse/jetty/http2/frames/Frame.java | 5 - .../jetty/http2/generator/DataGenerator.java | 9 +- .../jetty/http2/generator/FrameGenerator.java | 2 +- .../jetty/http2/generator/Generator.java | 13 +- .../http2/generator/GoAwayGenerator.java | 2 +- .../http2/generator/HeadersGenerator.java | 2 +- .../jetty/http2/generator/PingGenerator.java | 2 +- .../http2/generator/PriorityGenerator.java | 2 +- .../jetty/http2/generator/ResetGenerator.java | 2 +- .../http2/generator/SettingsGenerator.java | 2 +- .../generator/WindowUpdateGenerator.java | 2 +- .../jetty/http2/server/HTTP2ServerTest.java | 6 +- 18 files changed, 140 insertions(+), 86 deletions(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index 7ea80ccc374..8ceaa021318 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -44,6 +44,14 @@ import org.junit.Test; public class FlowControlTest extends AbstractTest { + @Override + public void dispose() throws Exception + { + // Allow WINDOW_UPDATE frames to be sent/received to avoid exception stack traces. + Thread.sleep(1000); + super.dispose(); + } + @Test public void testFlowControlWithConcurrentSettings() throws Exception { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index 8b0cf817fb7..811abf56e74 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -103,7 +103,7 @@ public class HTTP2FlowControl implements FlowControl // Negative streamId allow for generation of bytes for both stream and session int streamId = stream != null ? -stream.getId() : 0; WindowUpdateFrame frame = new WindowUpdateFrame(streamId, length); - session.frame(stream, frame, Callback.Adapter.INSTANCE); + session.control(stream, frame, Callback.Adapter.INSTANCE); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 3025c2ebf8c..b518b21ac9d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -117,14 +117,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (stream != null) { stream.updateClose(frame.isEndStream(), false); - flowControl.onDataReceived(this, stream, frame.getFlowControlledLength()); + final int length = frame.remaining(); + flowControl.onDataReceived(this, stream, length); return stream.process(frame, new Callback.Adapter() { @Override public void succeeded() { - int consumed = frame.getFlowControlledLength(); - flowControl.onDataConsumed(HTTP2Session.this, stream, consumed); + flowControl.onDataConsumed(HTTP2Session.this, stream, length); } }); } @@ -257,19 +257,19 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void settings(SettingsFrame frame, Callback callback) { - frame(null, frame, callback); + control(null, frame, callback); } @Override public void ping(PingFrame frame, Callback callback) { - frame(null, frame, callback); + control(null, frame, callback); } @Override public void reset(ResetFrame frame, Callback callback) { - frame(null, frame, callback); + control(null, frame, callback); } @Override @@ -278,15 +278,27 @@ public abstract class HTTP2Session implements ISession, Parser.Listener byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); LOG.debug("Sending {}: {}", frame.getType(), reason); - frame(null, frame, callback); + control(null, frame, callback); } @Override - public void frame(IStream stream, Frame frame, Callback callback) + public void control(IStream stream, Frame frame, Callback callback) { // We want to generate as late as possible to allow re-prioritization. - FlusherEntry entry = new FlusherEntry(stream, frame, callback); - LOG.debug("Sending {}", frame); + frame(new FlusherEntry(stream, frame, callback)); + } + + @Override + public void data(IStream stream, DataFrame frame, Callback callback) + { + // We want to generate as late as possible to allow re-prioritization. + frame(new DataFlusherEntry(stream, frame, callback)); + } + + private void frame(FlusherEntry entry) + { + if (LOG.isDebugEnabled()) + LOG.debug("Sending {}", entry.frame); flusher.append(entry); flusher.iterate(); } @@ -495,33 +507,38 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { FlusherEntry entry = queue.get(nonStalledIndex); IStream stream = entry.stream; - int frameWindow = entry.frame.getFlowControlledLength(); - if (frameWindow > 0) + int remaining = 0; + if (entry.frame instanceof DataFrame) { - // Is the session stalled ? - if (sessionWindow <= 0) + DataFrame dataFrame = (DataFrame)entry.frame; + remaining = dataFrame.remaining(); + if (remaining > 0) { - flowControl.onSessionStalled(HTTP2Session.this); - ++nonStalledIndex; - // There may be *non* flow controlled frames to send. - continue; - } - - if (stream != null) - { - Integer streamWindow = streams.get(stream); - if (streamWindow == null) + // Is the session stalled ? + if (sessionWindow <= 0) { - streamWindow = stream.getWindowSize(); - streams.put(stream, streamWindow); + flowControl.onSessionStalled(HTTP2Session.this); + ++nonStalledIndex; + // There may be *non* flow controlled frames to send. + continue; } - // Is it a frame belonging to an already stalled stream ? - if (streamWindow <= 0) + if (stream != null) { - flowControl.onStreamStalled(stream); - ++nonStalledIndex; - continue; + Integer streamWindow = streams.get(stream); + if (streamWindow == null) + { + streamWindow = stream.getWindowSize(); + streams.put(stream, streamWindow); + } + + // Is it a frame belonging to an already stalled stream ? + if (streamWindow <= 0) + { + flowControl.onStreamStalled(stream); + ++nonStalledIndex; + continue; + } } } } @@ -531,16 +548,16 @@ public abstract class HTTP2Session implements ISession, Parser.Listener --size; // If the stream has been reset, don't send flow controlled frames. - if (stream != null && stream.isReset() && frameWindow > 0) + if (stream != null && stream.isReset() && remaining > 0) { reset.add(entry); continue; } // Reduce the flow control windows. - sessionWindow -= frameWindow; - if (stream != null && frameWindow > 0) - streams.put(stream, streams.get(stream) - frameWindow); + sessionWindow -= remaining; + if (stream != null && remaining > 0) + streams.put(stream, streams.get(stream) - remaining); active.add(entry); if (active.size() == maxGather) @@ -630,10 +647,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private class FlusherEntry implements Callback { - private final IStream stream; - private final Frame frame; - private final Callback callback; - private int length; + protected final IStream stream; + protected final Frame frame; + protected final Callback callback; private FlusherEntry(IStream stream, Frame frame, Callback callback) { @@ -646,13 +662,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { try { - int windowSize = stream == null ? getWindowSize() : stream.getWindowSize(); - int frameLength = frame.getFlowControlledLength(); - if (frameLength > 0) - this.length = Math.min(frameLength, windowSize); - - generator.generate(lease, frame, windowSize); - LOG.debug("Generated {}, windowSize={}", frame, windowSize); + generator.control(lease, frame); + if (LOG.isDebugEnabled()) + LOG.debug("Generated {}", frame); } catch (Throwable x) { @@ -661,12 +673,46 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } + @Override + public void succeeded() + { + callback.succeeded(); + } + + @Override + public void failed(Throwable x) + { + callback.failed(x); + } + } + + private class DataFlusherEntry extends FlusherEntry + { + private int length; + + private DataFlusherEntry(IStream stream, DataFrame frame, Callback callback) + { + super(stream, frame, callback); + } + + public void generate(ByteBufferPool.Lease lease) + { + DataFrame dataFrame = (DataFrame)frame; + int windowSize = stream.getWindowSize(); + int frameLength = dataFrame.remaining(); + this.length = Math.min(frameLength, windowSize); + generator.data(lease, dataFrame, length); + if (LOG.isDebugEnabled()) + LOG.debug("Generated {}, maxLength={}", dataFrame, length); + } + @Override public void succeeded() { flowControl.onDataSent(HTTP2Session.this, stream, length); // Do we have more to send ? - if (frame.getFlowControlledLength() > 0) + DataFrame dataFrame = (DataFrame)frame; + if (dataFrame.remaining() > 0) { // We have written part of the frame, but there is more to write. // We need to keep the correct ordering of frames, to avoid that other @@ -675,19 +721,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } else { + // Only now we can update the close state + // and eventually remove the stream. + stream.updateClose(dataFrame.isEndStream(), true); + if (stream.isClosed()) + removeStream(stream, true); callback.succeeded(); - // TODO: what below is needed ? YES IT IS. -// stream.updateCloseState(dataInfo.isClose(), true); -// if (stream.isClosed()) -// removeStream(stream); } } - - @Override - public void failed(Throwable x) - { - callback.failed(x); - } } private class PromiseCallback implements Callback diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 41e176dd2f4..4133d77bd1d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -63,13 +63,13 @@ public class HTTP2Stream implements IStream @Override public void headers(HeadersFrame frame, Callback callback) { - session.frame(this, frame, callback); + session.control(this, frame, callback); } @Override public void data(DataFrame frame, Callback callback) { - session.frame(this, frame, callback); + session.data(this, frame, callback); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index 916dddc6cca..bd39cdb2602 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.http2; import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.util.Callback; @@ -27,7 +28,9 @@ public interface ISession extends Session @Override IStream getStream(int streamId); - public void frame(IStream stream, Frame frame, Callback callback); + public void control(IStream stream, Frame frame, Callback callback); + + public void data(IStream stream, DataFrame frame, Callback callback); public int updateWindowSize(int delta); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java index 73518b8f8ea..a754577bf60 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -49,8 +49,7 @@ public class DataFrame extends Frame return endStream; } - @Override - public int getFlowControlledLength() + public int remaining() { return data.remaining(); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java index 150d97aefc9..fa2f1945f4d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java @@ -35,11 +35,6 @@ public abstract class Frame return type; } - public int getFlowControlledLength() - { - return 0; - } - @Override public String toString() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index 465ddc6df35..8f6a3eac880 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -27,14 +27,15 @@ import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; -public class DataGenerator extends FrameGenerator +public class DataGenerator { + private final HeaderGenerator headerGenerator; + public DataGenerator(HeaderGenerator headerGenerator) { - super(headerGenerator); + this.headerGenerator = headerGenerator; } - @Override public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) { DataFrame dataFrame = (DataFrame)frame; @@ -82,7 +83,7 @@ public class DataGenerator extends FrameGenerator if (last) flags |= Flag.END_STREAM; - ByteBuffer header = generateHeader(lease, FrameType.DATA, length, flags, streamId); + ByteBuffer header = headerGenerator.generate(lease, FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags, streamId); BufferUtil.flipToFlush(header, 0); lease.append(header, true); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java index cc2bdb0e752..763d6ed703b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java @@ -33,7 +33,7 @@ public abstract class FrameGenerator this.headerGenerator = headerGenerator; } - public abstract void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength); + public abstract void generate(ByteBufferPool.Lease lease, Frame frame); protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int length, int flags, int streamId) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index f33c3fab884..21d98af10c5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.http2.generator; +import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.hpack.HpackEncoder; @@ -28,6 +29,7 @@ public class Generator private final ByteBufferPool byteBufferPool; private final int headerTableSize; private final FrameGenerator[] generators; + private final DataGenerator dataGenerator; public Generator(ByteBufferPool byteBufferPool) { @@ -43,7 +45,6 @@ public class Generator HpackEncoder encoder = new HpackEncoder(headerTableSize); this.generators = new FrameGenerator[FrameType.values().length]; - this.generators[FrameType.DATA.getType()] = new DataGenerator(headerGenerator); this.generators[FrameType.HEADERS.getType()] = new HeadersGenerator(headerGenerator, encoder); this.generators[FrameType.PRIORITY.getType()] = new PriorityGenerator(headerGenerator); this.generators[FrameType.RST_STREAM.getType()] = new ResetGenerator(headerGenerator); @@ -56,6 +57,7 @@ public class Generator this.generators[FrameType.ALTSVC.getType()] = null; // TODO this.generators[FrameType.BLOCKED.getType()] = null; // TODO + this.dataGenerator = new DataGenerator(headerGenerator); } public ByteBufferPool getByteBufferPool() @@ -68,8 +70,13 @@ public class Generator return headerTableSize; } - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void control(ByteBufferPool.Lease lease, Frame frame) { - generators[frame.getType().getType()].generate(lease, frame, maxLength); + generators[frame.getType().getType()].generate(lease, frame); + } + + public void data(ByteBufferPool.Lease lease, DataFrame frame, int maxLength) + { + dataGenerator.generate(lease, frame, maxLength); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index e3a2b1afc03..121059875f0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -35,7 +35,7 @@ public class GoAwayGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void generate(ByteBufferPool.Lease lease, Frame frame) { GoAwayFrame goAwayFrame = (GoAwayFrame)frame; generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index 1d4dc73e68b..d3671407736 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -40,7 +40,7 @@ public class HeadersGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void generate(ByteBufferPool.Lease lease, Frame frame) { HeadersFrame headersFrame = (HeadersFrame)frame; generate(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java index d3ce03cb735..ec5db1a151a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java @@ -35,7 +35,7 @@ public class PingGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void generate(ByteBufferPool.Lease lease, Frame frame) { PingFrame pingFrame = (PingFrame)frame; generatePing(lease, pingFrame.getPayload(), pingFrame.isReply()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java index 6faef2d664c..4ebb52d715f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java @@ -35,7 +35,7 @@ public class PriorityGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void generate(ByteBufferPool.Lease lease, Frame frame) { PriorityFrame priorityFrame = (PriorityFrame)frame; generatePriority(lease, priorityFrame.getStreamId(), priorityFrame.getDependentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java index 3cf0455d31a..781f29346d0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java @@ -35,7 +35,7 @@ public class ResetGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void generate(ByteBufferPool.Lease lease, Frame frame) { ResetFrame resetFrame = (ResetFrame)frame; generateReset(lease, resetFrame.getStreamId(), resetFrame.getError()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index a53d59b5e21..43971341750 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -36,7 +36,7 @@ public class SettingsGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void generate(ByteBufferPool.Lease lease, Frame frame) { SettingsFrame settingsFrame = (SettingsFrame)frame; generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply()); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java index f3eaa438a6c..e9be713989e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java @@ -35,7 +35,7 @@ public class WindowUpdateGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void generate(ByteBufferPool.Lease lease, Frame frame) { WindowUpdateFrame windowUpdateFrame = (WindowUpdateFrame)frame; generateWindowUpdate(lease, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta()); diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index c6845462b38..184b24cdce0 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -105,7 +105,7 @@ public class HTTP2ServerTest host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generate(lease, request, 0); + generator.control(lease, request); // No preface bytes @@ -154,7 +154,7 @@ public class HTTP2ServerTest host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generate(lease, request, 0); + generator.control(lease, request); lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); try (Socket client = new Socket(host, port)) @@ -217,7 +217,7 @@ public class HTTP2ServerTest host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generate(lease, request, 0); + generator.control(lease, request); lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); try (Socket client = new Socket(host, port)) From 8681511f085262b42e0a31234c9ec15cbfe3413f Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 17:10:38 +0200 Subject: [PATCH 072/269] Wrapping debug log statements with LOG.isDebugEnabled(). --- .../eclipse/jetty/http2/HTTP2FlowControl.java | 30 ++++++++++++------- .../org/eclipse/jetty/http2/HTTP2Session.java | 19 +++++++----- .../eclipse/jetty/http2/parser/Parser.java | 3 +- .../jetty/http2/parser/PrefaceParser.java | 3 +- .../jetty/http2/parser/ServerParser.java | 3 +- .../server/HTTP2ServerConnectionFactory.java | 6 ++-- .../http2/server/HttpTransportOverHTTP2.java | 15 ---------- 7 files changed, 42 insertions(+), 37 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index 811abf56e74..a57bce3ff3b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -57,13 +57,15 @@ public class HTTP2FlowControl implements FlowControl // Update the sessions's window size. int oldSize = session.updateWindowSize(delta); - LOG.debug("Updated session initial window {} -> {} for {}", oldSize, oldSize + delta, session); + if (LOG.isDebugEnabled()) + LOG.debug("Updated session initial window {} -> {} for {}", oldSize, oldSize + delta, session); // Update the streams' window size. for (Stream stream : session.getStreams()) { oldSize = ((IStream)stream).updateWindowSize(delta); - LOG.debug("Updated stream initial window {} -> {} for {}", oldSize, oldSize + delta, stream); + if (LOG.isDebugEnabled()) + LOG.debug("Updated stream initial window {} -> {} for {}", oldSize, oldSize + delta, stream); } } @@ -76,13 +78,15 @@ public class HTTP2FlowControl implements FlowControl if (stream != null) { int oldSize = stream.updateWindowSize(delta); - LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize + delta, stream); + if (LOG.isDebugEnabled()) + LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize + delta, stream); } } else { int oldSize = session.updateWindowSize(frame.getWindowDelta()); - LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize + delta, session); + if (LOG.isDebugEnabled()) + LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize + delta, session); } } @@ -99,7 +103,8 @@ public class HTTP2FlowControl implements FlowControl // We currently send a WindowUpdate every time, even if the frame was very small. // Other policies may send the WindowUpdate only upon reaching a threshold. - LOG.debug("Data consumed, increasing window by {} for {}", length, stream); + if (LOG.isDebugEnabled()) + LOG.debug("Data consumed, increasing window by {} for {}", length, stream); // Negative streamId allow for generation of bytes for both stream and session int streamId = stream != null ? -stream.getId() : 0; WindowUpdateFrame frame = new WindowUpdateFrame(streamId, length); @@ -112,25 +117,30 @@ public class HTTP2FlowControl implements FlowControl if (length == 0) return; - LOG.debug("Data sent, decreasing window by {}", length); + if (LOG.isDebugEnabled()) + LOG.debug("Data sent, decreasing window by {}", length); int oldSize = session.updateWindowSize(-length); - LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize - length, session); + if (LOG.isDebugEnabled()) + LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize - length, session); if (stream != null) { oldSize = stream.updateWindowSize(-length); - LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize - length, stream); + if (LOG.isDebugEnabled()) + LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize - length, stream); } } @Override public void onSessionStalled(ISession session) { - LOG.debug("Session stalled {}", session); + if (LOG.isDebugEnabled()) + LOG.debug("Session stalled {}", session); } @Override public void onStreamStalled(IStream stream) { - LOG.debug("Stream stalled {}", stream); + if (LOG.isDebugEnabled()) + LOG.debug("Stream stalled {}", stream); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index b518b21ac9d..c9b90796fbc 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -158,13 +158,13 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) { maxStreamCount = settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS); - LOG.debug("Updated max concurrent streams to {}", maxStreamCount); + if (LOG.isDebugEnabled()) + LOG.debug("Updated max concurrent streams to {}", maxStreamCount); } if (settings.containsKey(SettingsFrame.INITIAL_WINDOW_SIZE)) { int windowSize = settings.get(SettingsFrame.INITIAL_WINDOW_SIZE); flowControl.updateInitialWindowSize(this, windowSize); - LOG.debug("Updated initial window size to {}", windowSize); } // TODO: handle other settings notifySettings(this, frame); @@ -277,7 +277,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); - LOG.debug("Sending {}: {}", frame.getType(), reason); + if (LOG.isDebugEnabled()) + LOG.debug("Sending {}: {}", frame.getType(), reason); control(null, frame, callback); } @@ -305,7 +306,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener protected void disconnect() { - LOG.debug("Disconnecting"); + if (LOG.isDebugEnabled()) + LOG.debug("Disconnecting"); endPoint.close(); } @@ -316,7 +318,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (streams.putIfAbsent(streamId, stream) == null) { flowControl.onNewStream(stream); - LOG.debug("Created local {}", stream); + if (LOG.isDebugEnabled()) + LOG.debug("Created local {}", stream); return stream; } else @@ -350,7 +353,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { updateLastStreamId(streamId); flowControl.onNewStream(stream); - LOG.debug("Created remote {}", stream); + if (LOG.isDebugEnabled()) + LOG.debug("Created remote {}", stream); return stream; } else @@ -375,7 +379,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (local) streamCount.decrementAndGet(); - LOG.debug("Removed {}", stream); + if (LOG.isDebugEnabled()) + LOG.debug("Removed {}", stream); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index d74f797e00c..88cd6a9498f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -73,7 +73,8 @@ public class Parser public boolean parse(ByteBuffer buffer) { - LOG.debug("Parsing {}", buffer); + if (LOG.isDebugEnabled()) + LOG.debug("Parsing {}", buffer); while (true) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java index d5b6ee55164..6c5f635681b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java @@ -55,7 +55,8 @@ public class PrefaceParser if (cursor == PREFACE_BYTES.length) { cursor = 0; - LOG.debug("Parsed preface bytes"); + if (LOG.isDebugEnabled()) + LOG.debug("Parsed preface bytes"); return true; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java index f20328b30c4..80ea9610acc 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java @@ -42,7 +42,8 @@ public class ServerParser extends Parser @Override public boolean parse(ByteBuffer buffer) { - LOG.debug("Parsing {}", buffer); + if (LOG.isDebugEnabled()) + LOG.debug("Parsing {}", buffer); while (true) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 37307839e9f..5aa169481ca 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -81,7 +81,8 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { - LOG.debug("Processing {} on {}", frame, stream); + if (LOG.isDebugEnabled()) + LOG.debug("Processing {} on {}", frame, stream); HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2((IStream)stream, frame); HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); @@ -102,7 +103,8 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF @Override public void onData(Stream stream, DataFrame frame, Callback callback) { - LOG.debug("Processing {} on {}", frame, stream); + if (LOG.isDebugEnabled()) + LOG.debug("Processing {} on {}", frame, stream); HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(CHANNEL_ATTRIBUTE); channel.requestContent(frame, callback); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index cf9c94cfe9b..809b5f74034 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -55,21 +55,6 @@ public class HttpTransportOverHTTP2 implements HttpTransport boolean isHeadRequest = HttpMethod.HEAD.is(metaData.getMethod()); boolean hasContent = BufferUtil.hasContent(content) && !isHeadRequest; - // TODO: the idea here is this: - // CallbackLease lease = new CallbackLease(callback); - // commit(lease, ...) - // stream.header(lease, frame) - // session.frame(lease, frame) - // generator.generate(lease, frame) - // generateHeader(lease, frame); - // bodyGenerator[frame.getType()].generateBody(lease, frame); - // stream.content(lease, frame) - // ... - // flush(lease) - // - // Problem is that in this way I need to aggregate multiple callbacks for the same lease. - // So it'd need another abstraction that is a Lease+Callback - if (commit.compareAndSet(false, true)) { commit(info, !hasContent, !hasContent ? callback : new Callback.Adapter() From b3aa67e0a9ad7ef87647c8b7ec5609bd01798935 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 17:59:17 +0200 Subject: [PATCH 073/269] Implemented PING functionality. --- .../eclipse/jetty/http2/client/PingTest.java | 58 +++++++++++++ .../org/eclipse/jetty/http2/HTTP2Session.java | 26 +++++- .../jetty/http2/parser/PingBodyParser.java | 9 +- .../jetty/http2/server/HTTP2ServerTest.java | 82 +++++++++++++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java new file mode 100644 index 00000000000..0d612b639fc --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java @@ -0,0 +1,58 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.PingFrame; +import org.eclipse.jetty.util.Callback; +import org.junit.Assert; +import org.junit.Test; + +public class PingTest extends AbstractTest +{ + @Test + public void testPing() throws Exception + { + startServer(new ServerSessionListener.Adapter()); + + final byte[] payload = new byte[8]; + new Random().nextBytes(payload); + final CountDownLatch latch = new CountDownLatch(1); + Session client = newClient(new Session.Listener.Adapter() + { + @Override + public void onPing(Session session, PingFrame frame) + { + Assert.assertTrue(frame.isReply()); + Assert.assertArrayEquals(payload, frame.getPayload()); + latch.countDown(); + } + }); + + PingFrame frame = new PingFrame(payload, false); + client.ping(frame, Callback.Adapter.INSTANCE); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index c9b90796fbc..eeea767b3a6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -174,6 +174,15 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onPing(PingFrame frame) { + if (frame.isReply()) + { + notifyPing(this, frame); + } + else + { + PingFrame reply = new PingFrame(frame.getPayload(), true); + ping(reply, disconnectCallback); + } return false; } @@ -263,7 +272,10 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void ping(PingFrame frame, Callback callback) { - control(null, frame, callback); + if (frame.isReply()) + callback.failed(new IllegalArgumentException()); + else + control(null, frame, callback); } @Override @@ -438,6 +450,18 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } + protected void notifyPing(Session session, PingFrame frame) + { + try + { + listener.onPing(session, frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } + @Override public String toString() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 746d29deaaa..58fd1207de5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -50,11 +50,16 @@ public class PingBodyParser extends BodyParser { case PREPARE: { - int length = getBodyLength(); - if (length != 8) + // SPEC: wrong streamId is treated as connection error. + if (getStreamId() != 0) { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_ping_frame"); } + // SPEC: wrong body length is treated as connection error. + if (getBodyLength() != 8) + { + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_ping_frame"); + } state = State.PAYLOAD; break; } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 184b24cdce0..9fadfa8ca4f 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -40,12 +40,14 @@ import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.hpack.HpackContext; import org.eclipse.jetty.http2.hpack.HpackDecoder; import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; @@ -271,6 +273,86 @@ public class HTTP2ServerTest } } + @Test + public void testBadPingWrongPayload() throws Exception + { + startServer(new HttpServlet(){}); + + String host = "localhost"; + int port = connector.getLocalPort(); + PingFrame frame = new PingFrame(new byte[8], false); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.control(lease, frame); + // Modify the length of the frame to a wrong one. + lease.getByteBuffers().get(0).putShort(0, (short)7); + lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); + + final CountDownLatch latch = new CountDownLatch(1); + try (Socket client = new Socket(host, port)) + { + OutputStream output = client.getOutputStream(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + output.write(BufferUtil.toArray(buffer)); + } + + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onGoAway(GoAwayFrame frame) + { + Assert.assertEquals(ErrorCode.FRAME_SIZE_ERROR, frame.getError()); + latch.countDown(); + return false; + } + }); + + parseResponse(client, parser); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testBadPingWrongStreamId() throws Exception + { + startServer(new HttpServlet(){}); + + String host = "localhost"; + int port = connector.getLocalPort(); + PingFrame frame = new PingFrame(new byte[8], false); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.control(lease, frame); + // Modify the streamId of the frame to non zero. + lease.getByteBuffers().get(0).putInt(4, 1); + lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); + + final CountDownLatch latch = new CountDownLatch(1); + try (Socket client = new Socket(host, port)) + { + OutputStream output = client.getOutputStream(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + output.write(BufferUtil.toArray(buffer)); + } + + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onGoAway(GoAwayFrame frame) + { + Assert.assertEquals(ErrorCode.PROTOCOL_ERROR, frame.getError()); + latch.countDown(); + return false; + } + }); + + parseResponse(client, parser); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + } + private void parseResponse(Socket client, Parser parser) throws IOException { byte[] buffer = new byte[2048]; From a58a5f8268b7367da29f8385e73f1f84cdbff71e Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 22:57:40 +0200 Subject: [PATCH 074/269] Fixed handling of zero length body, that must be HPACK decoded. --- .../eclipse/jetty/http2/parser/HeadersBodyParser.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index aca43566ef5..54b12a2c21c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -24,6 +24,7 @@ import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.util.BufferUtil; public class HeadersBodyParser extends BodyParser { @@ -53,6 +54,15 @@ public class HeadersBodyParser extends BodyParser weight = 0; } + @Override + protected boolean emptyBody() + { + MetaData metaData = headerBlockParser.parse(BufferUtil.EMPTY_BUFFER, 0); + boolean result = onHeaders(0, 0, false, metaData); + reset(); + return result; + } + @Override public Result parse(ByteBuffer buffer) { From d4783369bc10231264abf10691002de50a7e0932 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 22:59:48 +0200 Subject: [PATCH 075/269] Fixed generation of sliced data frames, setting the end stream flag only when all the content has been generated. --- .../org/eclipse/jetty/http2/generator/DataGenerator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index 8f6a3eac880..2a6502a86f7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -67,10 +67,11 @@ public class DataGenerator int end = data.limit(); for (int i = 1; i <= frames; ++i) { - data.limit(begin + Math.min(dataBytesPerFrame * i, length)); + int limit = begin + Math.min(dataBytesPerFrame * i, length); + data.limit(limit); ByteBuffer slice = data.slice(); - data.position(data.limit()); - generateFrame(lease, streamId, slice, i == frames && last); + data.position(limit); + generateFrame(lease, streamId, slice, i == frames && last && limit == end); } data.limit(end); } From 2b86d34d5ac05035180c850d79b512145a9046d8 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 23:03:17 +0200 Subject: [PATCH 076/269] Properly closing the stream and eventually removing it when receiving data frames. --- .../src/main/java/org/eclipse/jetty/http2/HTTP2Session.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index eeea767b3a6..3f3353a818f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -119,7 +119,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener stream.updateClose(frame.isEndStream(), false); final int length = frame.remaining(); flowControl.onDataReceived(this, stream, length); - return stream.process(frame, new Callback.Adapter() + boolean result = stream.process(frame, new Callback.Adapter() { @Override public void succeeded() @@ -127,6 +127,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flowControl.onDataConsumed(HTTP2Session.this, stream, length); } }); + if (stream.isClosed()) + removeStream(stream, false); + return result; } else { From 363c18a29eef75ddbe9be1014d9891cf473eca83 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 23:03:37 +0200 Subject: [PATCH 077/269] Improved logging. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 16 ++++++++++++++++ .../jetty/http2/frames/WindowUpdateFrame.java | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 3f3353a818f..736cbb4332a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -112,6 +112,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onData(final DataFrame frame) { + if (LOG.isDebugEnabled()) + LOG.debug("Received {}", frame); int streamId = frame.getStreamId(); final IStream stream = getStream(streamId); if (stream != null) @@ -157,6 +159,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onSettings(SettingsFrame frame) { + if (LOG.isDebugEnabled()) + LOG.debug("Received {}", frame); Map settings = frame.getSettings(); if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) { @@ -177,6 +181,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onPing(PingFrame frame) { + if (LOG.isDebugEnabled()) + LOG.debug("Received {}", frame); if (frame.isReply()) { notifyPing(this, frame); @@ -221,6 +227,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onWindowUpdate(WindowUpdateFrame frame) { + if (LOG.isDebugEnabled()) + LOG.debug("Received {}", frame); int streamId = frame.getStreamId(); IStream stream = null; if (streamId > 0) @@ -616,6 +624,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } List byteBuffers = lease.getByteBuffers(); + if (LOG.isDebugEnabled()) + LOG.debug("Writing {} buffers ({} bytes) for {}", byteBuffers.size(), lease.getTotalLength(), active); endPoint.write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()])); return Action.SCHEDULED; } @@ -716,6 +726,12 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { callback.failed(x); } + + @Override + public String toString() + { + return frame.toString(); + } } private class DataFlusherEntry extends FlusherEntry diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java index ee0837ddc60..b5909dfa831 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java @@ -39,4 +39,10 @@ public class WindowUpdateFrame extends Frame { return windowDelta; } + + @Override + public String toString() + { + return String.format("%s{delta=%d}", super.toString(), windowDelta); + } } From 18c3e395df89f9885c7e82f86f65c625b49acf0c Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 23:03:49 +0200 Subject: [PATCH 078/269] More flow control tests. --- .../jetty/http2/client/FlowControlTest.java | 200 +++++++++--------- 1 file changed, 96 insertions(+), 104 deletions(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index 8ceaa021318..5f34b0cf76e 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.client; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit; @@ -220,18 +221,6 @@ public class FlowControlTest extends AbstractTest Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); } - private void checkThatWeAreFlowControlStalled(Exchanger exchanger) throws Exception - { - try - { - exchanger.exchange(null, 1, TimeUnit.SECONDS); - } - catch (TimeoutException x) - { - // Expected. - } - } - @Test public void testClientFlowControlOneBigWrite() throws Exception { @@ -328,145 +317,148 @@ public class FlowControlTest extends AbstractTest Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); } - // TODO: add tests for session and stream flow control. + private void checkThatWeAreFlowControlStalled(Exchanger exchanger) throws Exception + { + try + { + exchanger.exchange(null, 1, TimeUnit.SECONDS); + } + catch (TimeoutException x) + { + // Expected. + } + } -/* @Test - public void testStreamsStalledDoesNotStallOtherStreams() throws Exception + public void testSessionStalledStallsNewStreams() throws Exception { final int windowSize = 1024; final CountDownLatch settingsLatch = new CountDownLatch(1); - Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter() + startServer(new ServerSessionListener.Adapter() { @Override - public void onSettings(Session session, SettingsInfo settingsInfo) + public void onSettings(Session session, SettingsFrame frame) { settingsLatch.countDown(); } @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) + public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(new BytesDataInfo(new byte[windowSize * 2], true), new Callback.Adapter()); + // For every stream, send down half the window size of data. + MetaData.Response metaData = new MetaData.Response(200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(windowSize / 2), true); + stream.data(dataFrame, Callback.Adapter.INSTANCE); return null; } - }), null); - Settings settings = new Settings(); - settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize)); - session.settings(new SettingsInfo(settings)); + }); + + Session client = newClient(new Session.Listener.Adapter()); + + Map settings = new HashMap<>(); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize); + client.settings(new SettingsFrame(settings, false), Callback.Adapter.INSTANCE); Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); - final CountDownLatch latch = new CountDownLatch(3); - final AtomicReference dataInfoRef1 = new AtomicReference<>(); - final AtomicReference dataInfoRef2 = new AtomicReference<>(); - session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() - { - private final AtomicInteger dataFrames = new AtomicInteger(); + final AtomicReference callbackRef1 = new AtomicReference<>(); + final AtomicReference callbackRef2 = new AtomicReference<>(); + // First request will consume half the session window. + MetaData.Request request1 = newRequest("GET", new HttpFields()); + client.newStream(new HeadersFrame(0, request1, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() + { @Override - public void onData(Stream stream, DataInfo dataInfo) + public void onData(Stream stream, DataFrame frame, Callback callback) { - int frames = dataFrames.incrementAndGet(); - if (frames == 1) - { - // Do not consume it to stall flow control - dataInfoRef1.set(dataInfo); - } - else - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - latch.countDown(); - } + // Do not consume it to stall flow control. + callbackRef1.set(callback); } }); - session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() - { - private final AtomicInteger dataFrames = new AtomicInteger(); + // Second request will consume the session window, which is now stalled. + // A third request will not be able to receive data. + MetaData.Request request2 = newRequest("GET", new HttpFields()); + client.newStream(new HeadersFrame(0, request2, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() + { @Override - public void onData(Stream stream, DataInfo dataInfo) + public void onData(Stream stream, DataFrame frame, Callback callback) { - int frames = dataFrames.incrementAndGet(); - if (frames == 1) - { - // Do not consume it to stall flow control - dataInfoRef2.set(dataInfo); - } - else - { - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) - latch.countDown(); - } + // Do not consume it to stall flow control. + callbackRef2.set(callback); } }); - session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter() + + // Third request is now stalled. + final CountDownLatch latch = new CountDownLatch(1); + MetaData.Request request3 = newRequest("GET", new HttpFields()); + client.newStream(new HeadersFrame(0, request3, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() { @Override - public void onData(Stream stream, DataInfo dataInfo) + public void onData(Stream stream, DataFrame frame, Callback callback) { - DataInfo dataInfo1 = dataInfoRef1.getAndSet(null); - if (dataInfo1 != null) - dataInfo1.consume(dataInfo1.length()); - DataInfo dataInfo2 = dataInfoRef2.getAndSet(null); - if (dataInfo2 != null) - dataInfo2.consume(dataInfo2.length()); - dataInfo.consume(dataInfo.length()); - if (dataInfo.isClose()) + callback.succeeded(); + if (frame.isEndStream()) latch.countDown(); } }); + // Verify that the data does not arrive because the server session is stalled. + Assert.assertFalse(latch.await(1, TimeUnit.SECONDS)); + + // Consume the data of the second response. + // This will open up the session window, allowing the third stream to send data. + Callback callback2 = callbackRef2.getAndSet(null); + if (callback2 != null) + callback2.succeeded(); + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } @Test - public void testSendBigFileWithoutFlowControl() throws Exception + public void testServerSendsBigContent() throws Exception { - testSendBigFile(SPDY.V2); - } + final byte[] data = new byte[1024 * 1024]; + new Random().nextBytes(data); - @Test - public void testSendBigFileWithFlowControl() throws Exception - { - testSendBigFile(SPDY.V3); - } - - private void testSendBigFile(short version) throws Exception - { - final int dataSize = 1024 * 1024; - final ByteBufferDataInfo bigByteBufferDataInfo = new ByteBufferDataInfo(ByteBuffer.allocate(dataSize),false); - final CountDownLatch allDataReceivedLatch = new CountDownLatch(1); - - Session session = startClient(version, startServer(version, new ServerSessionFrameListener.Adapter() + startServer(new ServerSessionListener.Adapter() { @Override - public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) + public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - stream.reply(new ReplyInfo(false), new Callback.Adapter()); - stream.data(bigByteBufferDataInfo, new Callback.Adapter()); + MetaData.Response metaData = new MetaData.Response(200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.wrap(data), true); + stream.data(dataFrame, Callback.Adapter.INSTANCE); return null; } - }),new SessionFrameListener.Adapter()); - - session.syn(new SynInfo(new Fields(), false),new StreamFrameListener.Adapter() - { - private int dataBytesReceived; - - @Override - public void onData(Stream stream, DataInfo dataInfo) - { - dataBytesReceived = dataBytesReceived + dataInfo.length(); - dataInfo.consume(dataInfo.length()); - if (dataBytesReceived == dataSize) - allDataReceivedLatch.countDown(); - } }); - assertThat("all data bytes have been received by the client", allDataReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); + Session client = newClient(new Session.Listener.Adapter()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + final byte[] bytes = new byte[data.length]; + final CountDownLatch latch = new CountDownLatch(1); + client.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter() + { + private int received; + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + int remaining = frame.remaining(); + frame.getData().get(bytes, received, remaining); + this.received += remaining; + callback.succeeded(); + if (frame.isEndStream()) + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + Assert.assertArrayEquals(data, bytes); } -*/ } From 75b0a7088b8ba8dcdad70cd22c35f74064b24043 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 13 Jun 2014 23:13:26 +0200 Subject: [PATCH 079/269] Fixed onPing() method: replaced call to ping() with control() since ping() should not be called to reply to a ping. --- .../src/main/java/org/eclipse/jetty/http2/HTTP2Session.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 736cbb4332a..5b5f65bda22 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -190,7 +190,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener else { PingFrame reply = new PingFrame(frame.getPayload(), true); - ping(reply, disconnectCallback); + control(null, reply, disconnectCallback); } return false; } From a500701bda2d3c009d6e8f1ecb9210907aec1de3 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Sun, 15 Jun 2014 16:39:23 +0200 Subject: [PATCH 080/269] Fixed notification of Session's promise upon connect: it must be notified only after we have successfully sent the preface bytes. --- .../jetty/http2/client/HTTP2Client.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index b5853973e22..1da1295256a 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -120,19 +120,19 @@ public class HTTP2Client extends ContainerLifeCycle Generator generator = new Generator(byteBufferPool, 4096); HTTP2Session session = new HTTP2ClientSession(endpoint, generator, context.listener, new HTTP2FlowControl(65535)); Parser parser = new Parser(byteBufferPool, session); - Connection connection = new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, 8192, session); - context.promise.succeeded(session); - return connection; + return new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, 8192, context.promise, session); } } - private class HTTP2ClientConnection extends HTTP2Connection + private class HTTP2ClientConnection extends HTTP2Connection implements Callback { + private final Promise promise; private final Session session; - public HTTP2ClientConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, int bufferSize, Session session) + public HTTP2ClientConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, int bufferSize, Promise promise, Session session) { super(byteBufferPool, executor, endpoint, parser, bufferSize); + this.promise = promise; this.session = session; } @@ -140,8 +140,7 @@ public class HTTP2Client extends ContainerLifeCycle public void onOpen() { super.onOpen(); - sessions.offer(session); - getEndPoint().write(Callback.Adapter.INSTANCE, ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES)); + getEndPoint().write(this, ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES)); } @Override @@ -150,6 +149,20 @@ public class HTTP2Client extends ContainerLifeCycle super.onClose(); sessions.remove(session); } + + @Override + public void succeeded() + { + sessions.offer(session); + promise.succeeded(session); + } + + @Override + public void failed(Throwable x) + { + close(); + promise.failed(x); + } } private class Context From 7613385578e07417bb8cb9acc55f14bd093c8275 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 12:44:12 +0200 Subject: [PATCH 081/269] Moved NPN[Client|Server]Connection[Factory] classes to their own modules, akin for the ALPN classes, and refactored all code that was referencing them. --- .../eclipse/jetty/embedded/SpdyConnector.java | 8 +- .../eclipse/jetty/embedded/SpdyServer.java | 6 +- jetty-alpn/jetty-alpn-client/pom.xml | 4 +- jetty-alpn/jetty-alpn-server/pom.xml | 4 +- jetty-alpn/pom.xml | 2 - jetty-distribution/pom.xml | 5 + jetty-http2/http2-server/pom.xml | 20 ++-- .../jetty/http2/server/Http2Server.java | 26 ++---- jetty-npn/jetty-npn-client/pom.xml | 74 +++++++++++++++ .../npn}/client/NPNClientConnection.java | 2 +- .../client/NPNClientConnectionFactory.java | 2 +- jetty-npn/jetty-npn-server/pom.xml | 92 +++++++++++++++++++ .../src/main/config/etc/protonego-npn.xml | 21 +++++ .../modules/protonego-impl/npn-1.7.0_04.mod | 0 .../modules/protonego-impl/npn-1.7.0_05.mod | 0 .../modules/protonego-impl/npn-1.7.0_06.mod | 0 .../modules/protonego-impl/npn-1.7.0_07.mod | 0 .../modules/protonego-impl/npn-1.7.0_09.mod | 0 .../modules/protonego-impl/npn-1.7.0_10.mod | 0 .../modules/protonego-impl/npn-1.7.0_11.mod | 0 .../modules/protonego-impl/npn-1.7.0_13.mod | 0 .../modules/protonego-impl/npn-1.7.0_15.mod | 0 .../modules/protonego-impl/npn-1.7.0_17.mod | 0 .../modules/protonego-impl/npn-1.7.0_21.mod | 0 .../modules/protonego-impl/npn-1.7.0_25.mod | 0 .../modules/protonego-impl/npn-1.7.0_40.mod | 0 .../modules/protonego-impl/npn-1.7.0_45.mod | 0 .../modules/protonego-impl/npn-1.7.0_51.mod | 0 .../modules/protonego-impl/npn-1.7.0_55.mod | 0 .../modules/protonego-impl/npn-1.7.0_60.mod | 0 .../config/modules/protonego-impl/npn.mod | 4 + .../npn}/server/NPNServerConnection.java | 2 +- .../server/NPNServerConnectionFactory.java | 2 +- jetty-npn/pom.xml | 15 +++ .../NegotiatingServerConnectionFactory.java | 24 ++++- jetty-spdy/spdy-client/pom.xml | 5 + .../eclipse/jetty/spdy/client/SPDYClient.java | 1 + .../src/main/config/example-jetty-spdy.xml | 2 +- jetty-spdy/spdy-http-server/pom.xml | 6 ++ .../src/main/config/etc/protonego-npn.xml | 21 ----- .../server/http/HTTPSPDYServerConnector.java | 2 +- .../proxy/HTTPSPDYProxyServerConnector.java | 2 +- .../server/http/ReferrerPushStrategyTest.java | 11 +-- jetty-spdy/spdy-npn-tests/pom.xml | 6 ++ .../proxy/NPNProxySPDYToHTTPLoadTest.java | 2 +- jetty-spdy/spdy-server/pom.xml | 5 + .../server/SPDYServerConnectionFactory.java | 31 ------- .../spdy/server/SPDYServerConnector.java | 1 + .../jetty/spdy/server/AbstractTest.java | 1 + pom.xml | 7 +- .../jetty/TestTransparentProxyServer.java | 6 +- 51 files changed, 307 insertions(+), 115 deletions(-) create mode 100644 jetty-npn/jetty-npn-client/pom.xml rename {jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy => jetty-npn/jetty-npn-client/src/main/java/org/eclipse/jetty/npn}/client/NPNClientConnection.java (98%) rename {jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy => jetty-npn/jetty-npn-client/src/main/java/org/eclipse/jetty/npn}/client/NPNClientConnectionFactory.java (97%) create mode 100644 jetty-npn/jetty-npn-server/pom.xml create mode 100644 jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn.mod (91%) rename {jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy => jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn}/server/NPNServerConnection.java (98%) rename {jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy => jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn}/server/NPNServerConnectionFactory.java (98%) create mode 100644 jetty-npn/pom.xml delete mode 100644 jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java index 05115382c77..e4853c264c4 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java @@ -18,14 +18,14 @@ package org.eclipse.jetty.embedded; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -72,8 +72,8 @@ public class SpdyConnector new HTTPSPDYServerConnectionFactory(3,https_config,new ReferrerPushStrategy()); // NPN Factory - SPDYServerConnectionFactory.checkProtocolNegotiationAvailable(); - NPNServerConnectionFactory npn = + NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable(); + NPNServerConnectionFactory npn = new NPNServerConnectionFactory(spdy3.getProtocol(),spdy2.getProtocol(),http.getDefaultProtocol()); npn.setDefaultProtocol(http.getDefaultProtocol()); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java index a9dfdc488f4..5e6e448d293 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java @@ -23,6 +23,7 @@ import java.lang.management.ManagementFactory; import org.eclipse.jetty.deploy.DeploymentManager; import org.eclipse.jetty.deploy.providers.WebAppProvider; import org.eclipse.jetty.jmx.MBeanContainer; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; import org.eclipse.jetty.security.HashLoginService; import org.eclipse.jetty.server.AsyncNCSARequestLog; import org.eclipse.jetty.server.ForwardedRequestCustomizer; @@ -30,6 +31,7 @@ import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.NCSARequestLog; +import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -39,8 +41,6 @@ import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.handler.StatisticsHandler; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.http.PushStrategy; import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy; @@ -110,7 +110,7 @@ public class SpdyServer // Spdy Connector // Make sure that the required NPN implementations are available. - SPDYServerConnectionFactory.checkProtocolNegotiationAvailable(); + NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable(); // A ReferrerPushStrategy is being initialized. // See: http://www.eclipse.org/jetty/documentation/current/spdy-configuring-push.html for more details. diff --git a/jetty-alpn/jetty-alpn-client/pom.xml b/jetty-alpn/jetty-alpn-client/pom.xml index bc8b9059e38..1f8b0b960e6 100644 --- a/jetty-alpn/jetty-alpn-client/pom.xml +++ b/jetty-alpn/jetty-alpn-client/pom.xml @@ -6,9 +6,7 @@ 4.0.0 jetty-alpn-client - Jetty :: ALPN Client - Jetty ALPN client services - http://www.eclipse.org/jetty + Jetty :: ALPN :: Client ${project.groupId}.alpn.client diff --git a/jetty-alpn/jetty-alpn-server/pom.xml b/jetty-alpn/jetty-alpn-server/pom.xml index a5b0a1e7719..537fc2177ba 100644 --- a/jetty-alpn/jetty-alpn-server/pom.xml +++ b/jetty-alpn/jetty-alpn-server/pom.xml @@ -6,9 +6,7 @@ 4.0.0 jetty-alpn-server - Jetty :: ALPN Server - Jetty ALPN server services - http://www.eclipse.org/jetty + Jetty :: ALPN :: Server ${project.groupId}.alpn.server diff --git a/jetty-alpn/pom.xml b/jetty-alpn/pom.xml index 179b06624e7..c5403fcc4bd 100644 --- a/jetty-alpn/pom.xml +++ b/jetty-alpn/pom.xml @@ -8,8 +8,6 @@ jetty-alpn-parent pom Jetty :: ALPN :: Parent - Jetty ALPN services parent - http://www.eclipse.org/jetty jetty-alpn-server jetty-alpn-client diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index 2bc14963c46..aa0fb5b8c26 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -813,6 +813,11 @@ jetty-alpn-server ${project.version} + + org.eclipse.jetty + jetty-npn-server + ${project.version} + org.eclipse.jetty.example-async-rest example-async-rest-webapp diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index 8a26f2ec76c..3141e017a46 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -54,11 +54,6 @@ jetty-server ${project.version} - - org.eclipse.jetty.toolchain - jetty-test-helper - test - org.eclipse.jetty jetty-servlet @@ -66,15 +61,20 @@ test - org.eclipse.jetty.spdy - spdy-server + org.eclipse.jetty + jetty-alpn-server ${project.version} test - org.eclipse.jetty.npn - npn-api - ${npn.api.version} + org.eclipse.jetty.alpn + alpn-api + ${alpn.api.version} + test + + + org.eclipse.jetty.toolchain + jetty-test-helper test diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java index 83019da8c87..e5965e2d50f 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.http2.server; import java.io.IOException; import java.util.Date; - import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -29,14 +28,11 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.hpack.HpackContext; -import org.eclipse.jetty.http2.hpack.HpackDecoder; -import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.npn.NextProtoNego; +import org.eclipse.jetty.alpn.ALPN; +import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -44,8 +40,6 @@ import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -92,21 +86,21 @@ public class Http2Server // HTTP2 factory HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); - SPDYServerConnectionFactory.checkProtocolNegotiationAvailable(); - NPNServerConnectionFactory npn = - new NPNServerConnectionFactory(h2.getProtocol(),http.getDefaultProtocol()); - npn.setDefaultProtocol(http.getDefaultProtocol()); + NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable(); + ALPNServerConnectionFactory alpn = + new ALPNServerConnectionFactory(h2.getProtocol(),http.getDefaultProtocol()); + alpn.setDefaultProtocol(http.getDefaultProtocol()); // SSL Factory - SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,npn.getProtocol()); + SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol()); // SPDY Connector ServerConnector http2Connector = - new ServerConnector(server,ssl,npn,h2,new HttpConnectionFactory(https_config)); + new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config)); http2Connector.setPort(8443); server.addConnector(http2Connector); - NextProtoNego.debug=true; + ALPN.debug=true; server.start(); server.dumpStdErr(); diff --git a/jetty-npn/jetty-npn-client/pom.xml b/jetty-npn/jetty-npn-client/pom.xml new file mode 100644 index 00000000000..bf9b4564225 --- /dev/null +++ b/jetty-npn/jetty-npn-client/pom.xml @@ -0,0 +1,74 @@ + + + org.eclipse.jetty + jetty-npn-parent + 10.0.0-SNAPSHOT + + 4.0.0 + jetty-npn-client + Jetty :: NPN :: Client + + ${project.groupId}.npn.client + + + + + org.apache.felix + maven-bundle-plugin + true + + + + manifest + + + + org.eclipse.jetty.npn;resolution:=optional + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + org.apache.maven.plugins + maven-source-plugin + + + org.codehaus.mojo + findbugs-maven-plugin + + org.eclipse.jetty.npn.* + + + + + + + org.eclipse.jetty + jetty-io + ${project.version} + + + org.eclipse.jetty.npn + npn-api + ${npn.api.version} + provided + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java b/jetty-npn/jetty-npn-client/src/main/java/org/eclipse/jetty/npn/client/NPNClientConnection.java similarity index 98% rename from jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java rename to jetty-npn/jetty-npn-client/src/main/java/org/eclipse/jetty/npn/client/NPNClientConnection.java index 69c11d835da..c2519511019 100644 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java +++ b/jetty-npn/jetty-npn-client/src/main/java/org/eclipse/jetty/npn/client/NPNClientConnection.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.spdy.client; +package org.eclipse.jetty.npn.client; import java.util.List; import java.util.Map; diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java b/jetty-npn/jetty-npn-client/src/main/java/org/eclipse/jetty/npn/client/NPNClientConnectionFactory.java similarity index 97% rename from jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java rename to jetty-npn/jetty-npn-client/src/main/java/org/eclipse/jetty/npn/client/NPNClientConnectionFactory.java index 2a7d332fa5b..91156af2e90 100644 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java +++ b/jetty-npn/jetty-npn-client/src/main/java/org/eclipse/jetty/npn/client/NPNClientConnectionFactory.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.spdy.client; +package org.eclipse.jetty.npn.client; import java.io.IOException; import java.util.Map; diff --git a/jetty-npn/jetty-npn-server/pom.xml b/jetty-npn/jetty-npn-server/pom.xml new file mode 100644 index 00000000000..9554de4f0d6 --- /dev/null +++ b/jetty-npn/jetty-npn-server/pom.xml @@ -0,0 +1,92 @@ + + + org.eclipse.jetty + jetty-npn-parent + 10.0.0-SNAPSHOT + + 4.0.0 + jetty-npn-server + Jetty :: NPN :: Server + + ${project.groupId}.npn.server + + + + + org.apache.felix + maven-bundle-plugin + true + + + + manifest + + + + org.eclipse.jetty.npn,* + <_nouses>true + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + config + + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + org.codehaus.mojo + findbugs-maven-plugin + + org.eclipse.jetty.npn.* + + + + + + + org.eclipse.jetty + jetty-server + ${project.version} + + + org.eclipse.jetty.npn + npn-api + ${npn.api.version} + provided + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + diff --git a/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml b/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml new file mode 100644 index 00000000000..743a5ecd6f1 --- /dev/null +++ b/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml @@ -0,0 +1,21 @@ + + + + + + + spdy/3 + spdy/2 + http/1.1 + + + + http/1.1 + + + + + + diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod similarity index 91% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod index 040aad10197..f9d02061fb1 100644 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod +++ b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod @@ -23,6 +23,10 @@ protonego-impl [depend] protonego-impl/npn-${java.version} +[lib] +lib/jetty-npn-client-${jetty.version}.jar +lib/jetty-npn-server-${jetty.version}.jar + [xml] etc/protonego-npn.xml diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnection.java similarity index 98% rename from jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java rename to jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnection.java index 1a9e291e0a6..5ba752dae7c 100644 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java +++ b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnection.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.spdy.server; +package org.eclipse.jetty.npn.server; import java.util.List; import javax.net.ssl.SSLEngine; diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java similarity index 98% rename from jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java rename to jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java index c69f0fcd9e5..8c1cb190c54 100644 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java +++ b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.spdy.server; +package org.eclipse.jetty.npn.server; import java.util.List; import javax.net.ssl.SSLEngine; diff --git a/jetty-npn/pom.xml b/jetty-npn/pom.xml new file mode 100644 index 00000000000..163f0c7439a --- /dev/null +++ b/jetty-npn/pom.xml @@ -0,0 +1,15 @@ + + + org.eclipse.jetty + jetty-project + 10.0.0-SNAPSHOT + + 4.0.0 + jetty-npn-parent + pom + Jetty :: NPN :: Parent + + jetty-npn-server + jetty-npn-client + + diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java index f826d711529..08c8817189e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java @@ -27,11 +27,31 @@ import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.ssl.SslConnection; -import org.eclipse.jetty.server.AbstractConnectionFactory; -import org.eclipse.jetty.server.Connector; public abstract class NegotiatingServerConnectionFactory extends AbstractConnectionFactory { + public static void checkProtocolNegotiationAvailable() + { + if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN") && + !isAvailableInBootClassPath("org.eclipse.jetty.npn.NextProtoNego")) + throw new IllegalStateException("No ALPN nor NPN classes available"); + } + + private static boolean isAvailableInBootClassPath(String className) + { + try + { + Class klass = ClassLoader.getSystemClassLoader().loadClass(className); + if (klass.getClassLoader() != null) + throw new IllegalStateException(className + " must be on JVM boot classpath"); + return true; + } + catch (ClassNotFoundException x) + { + return false; + } + } + private final List protocols; private String defaultProtocol; diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml index e70e92ca5fd..b883aeb72c7 100644 --- a/jetty-spdy/spdy-client/pom.xml +++ b/jetty-spdy/spdy-client/pom.xml @@ -49,6 +49,11 @@ jetty-alpn-client ${project.version} + + org.eclipse.jetty + jetty-npn-client + ${project.version} + org.eclipse.jetty.alpn alpn-api diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java index b810e5cff43..e39e6856afd 100644 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java +++ b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java @@ -41,6 +41,7 @@ import org.eclipse.jetty.io.NegotiatingClientConnectionFactory; import org.eclipse.jetty.io.SelectChannelEndPoint; import org.eclipse.jetty.io.SelectorManager; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; +import org.eclipse.jetty.npn.client.NPNClientConnectionFactory; import org.eclipse.jetty.spdy.FlowControlStrategy; import org.eclipse.jetty.spdy.api.GoAwayInfo; import org.eclipse.jetty.spdy.api.Session; diff --git a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml b/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml index 47f83be8256..28419885168 100644 --- a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml +++ b/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml @@ -84,7 +84,7 @@ - + spdy/3 diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml index 31565522f89..fda057be235 100644 --- a/jetty-spdy/spdy-http-server/pom.xml +++ b/jetty-spdy/spdy-http-server/pom.xml @@ -86,6 +86,12 @@ jetty-client ${project.version} + + org.eclipse.jetty + jetty-npn-server + ${project.version} + + org.eclipse.jetty jetty-servlet diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml deleted file mode 100644 index 6e30f39ed60..00000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - spdy/3 - spdy/2 - http/1.1 - - - - http/1.1 - - - - - - diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java index c68172d8a5c..cd3f06ba5bf 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.spdy.server.http; import java.util.Collections; import java.util.Map; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; import org.eclipse.jetty.server.AbstractConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.HttpConfiguration; @@ -28,7 +29,6 @@ import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; public class HTTPSPDYServerConnector extends ServerConnector diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java index 65d16e2ed2d..44222bed332 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java @@ -21,12 +21,12 @@ package org.eclipse.jetty.spdy.server.proxy; import java.util.Objects; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.spdy.api.SPDY; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java index 0b8907e8daf..eec770d7504 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java @@ -18,10 +18,6 @@ package org.eclipse.jetty.spdy.server.http; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - import java.io.IOException; import java.io.PrintWriter; import java.net.InetSocketAddress; @@ -31,12 +27,12 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.Request; @@ -57,7 +53,6 @@ import org.eclipse.jetty.spdy.api.StreamFrameListener; import org.eclipse.jetty.spdy.api.StreamStatus; import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Promise; @@ -68,6 +63,10 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; + public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest { private static final Logger LOG = Log.getLogger(ReferrerPushStrategyTest.class); diff --git a/jetty-spdy/spdy-npn-tests/pom.xml b/jetty-spdy/spdy-npn-tests/pom.xml index 5634fec5df7..60782fd0048 100644 --- a/jetty-spdy/spdy-npn-tests/pom.xml +++ b/jetty-spdy/spdy-npn-tests/pom.xml @@ -52,6 +52,12 @@ ${npn.api.version} provided + + org.eclipse.jetty + jetty-npn-server + ${project.version} + test + org.eclipse.jetty jetty-start diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java index 355c597744f..6ed3dd831bc 100644 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java @@ -18,7 +18,7 @@ package org.eclipse.jetty.spdy.server.proxy; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; public class NPNProxySPDYToHTTPLoadTest extends ProxySPDYToHTTPLoadTest { diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index 4e50110c334..e4bc43e1be0 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -55,6 +55,11 @@ jetty-server ${project.version} + + org.eclipse.jetty + jetty-npn-server + ${project.version} + org.eclipse.jetty.npn npn-api diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java index 7d15ab168b3..c4ed673308d 100644 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java @@ -47,37 +47,6 @@ import org.eclipse.jetty.util.annotation.ManagedObject; @ManagedObject("SPDY Server Connection Factory") public class SPDYServerConnectionFactory extends AbstractConnectionFactory { - /** - * @deprecated use {@link #checkProtocolNegotiationAvailable()} instead. - */ - @Deprecated - public static void checkNPNAvailable() - { - checkProtocolNegotiationAvailable(); - } - - public static void checkProtocolNegotiationAvailable() - { - if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN") && - !isAvailableInBootClassPath("org.eclipse.jetty.npn.NextProtoNego")) - throw new IllegalStateException("No ALPN nor NPN classes available"); - } - - private static boolean isAvailableInBootClassPath(String className) - { - try - { - Class klass = ClassLoader.getSystemClassLoader().loadClass(className); - if (klass.getClassLoader() != null) - throw new IllegalStateException(className + " must be on JVM boot classpath"); - return true; - } - catch (ClassNotFoundException x) - { - return false; - } - } - private final Queue sessions = new ConcurrentLinkedQueue<>(); private final short version; private final ServerSessionFrameListener listener; diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java index cf73fe9fcbb..827bb5a06c9 100644 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.spdy.server; import java.util.Objects; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.server.Server; diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java index e5b21202756..19479fa31a4 100644 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java +++ b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java @@ -22,6 +22,7 @@ package org.eclipse.jetty.spdy.server; import java.net.InetSocketAddress; import java.util.concurrent.Executor; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; diff --git a/pom.xml b/pom.xml index 3481c34ad18..75715000d4c 100644 --- a/pom.xml +++ b/pom.xml @@ -456,10 +456,11 @@ jetty-http-spi jetty-osgi jetty-alpn + jetty-npn - + diff --git a/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java b/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java index b1be102f65a..8cf38d51195 100644 --- a/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java +++ b/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java @@ -21,10 +21,12 @@ package org.eclipse.jetty; import java.lang.management.ManagementFactory; import org.eclipse.jetty.jmx.MBeanContainer; +import org.eclipse.jetty.npn.server.NPNServerConnectionFactory; import org.eclipse.jetty.server.ForwardedRequestCustomizer; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -32,8 +34,6 @@ import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; -import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.http.PushStrategy; import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy; @@ -102,7 +102,7 @@ public class TestTransparentProxyServer // Spdy Connector - SPDYServerConnectionFactory.checkProtocolNegotiationAvailable(); + NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable(); PushStrategy push = new ReferrerPushStrategy(); HTTPSPDYServerConnectionFactory spdy2 = new HTTPSPDYServerConnectionFactory(2,config,push); spdy2.setInputBufferSize(8192); From 907d3037743cf00e09c41a8936d7924e9d9733ac Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 10:38:01 +0200 Subject: [PATCH 082/269] Added checks on the validity of the streamId. --- .../java/org/eclipse/jetty/http2/parser/DataBodyParser.java | 5 +++++ .../org/eclipse/jetty/http2/parser/HeadersBodyParser.java | 5 +++++ .../org/eclipse/jetty/http2/parser/PriorityBodyParser.java | 5 +++++ .../java/org/eclipse/jetty/http2/parser/ResetBodyParser.java | 5 +++++ .../org/eclipse/jetty/http2/parser/SettingsBodyParser.java | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index 3a2e111e0e8..a90e17383c0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -62,6 +62,11 @@ public class DataBodyParser extends BodyParser { case PREPARE: { + // SPEC: wrong streamId is treated as connection error. + if (getStreamId() == 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame"); + } length = getBodyLength(); if (isPaddingHigh()) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 54b12a2c21c..7c66e91caa0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -73,6 +73,11 @@ public class HeadersBodyParser extends BodyParser { case PREPARE: { + // SPEC: wrong streamId is treated as connection error. + if (getStreamId() == 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + } length = getBodyLength(); if (isPaddingHigh()) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index b845266273a..1389e1df168 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -51,6 +51,11 @@ public class PriorityBodyParser extends BodyParser { case PREPARE: { + // SPEC: wrong streamId is treated as connection error. + if (getStreamId() == 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_priority_frame"); + } int length = getBodyLength(); if (length != 5) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java index f74456eb384..15c1e8b1bbc 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java @@ -49,6 +49,11 @@ public class ResetBodyParser extends BodyParser { case PREPARE: { + // SPEC: wrong streamId is treated as connection error. + if (getStreamId() == 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_rst_stream_frame"); + } int length = getBodyLength(); if (length != 4) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index d1649fc4dbd..0db05d10bc9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -64,6 +64,11 @@ public class SettingsBodyParser extends BodyParser { case PREPARE: { + // SPEC: wrong streamId is treated as connection error. + if (getStreamId() != 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); + } length = getBodyLength(); settings = new HashMap<>(); state = State.SETTING_ID; From 849360717e382aeb2bd7d7f43bca10755392e4a1 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 11:10:55 +0200 Subject: [PATCH 083/269] Implemented PUSH_PROMISE generator/parser. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 8 + .../jetty/http2/frames/PushPromiseFrame.java | 51 +++++ .../jetty/http2/generator/Generator.java | 2 +- .../http2/generator/HeadersGenerator.java | 4 +- .../http2/generator/PushPromiseGenerator.java | 55 +++++ .../jetty/http2/parser/BodyParser.java | 14 ++ .../eclipse/jetty/http2/parser/Parser.java | 11 +- .../http2/parser/PushPromiseBodyParser.java | 190 ++++++++++++++++++ .../frames/HeadersGenerateParseTest.java | 116 ++++++++++- .../frames/PushPromiseGenerateParseTest.java | 150 ++++++++++++++ 10 files changed, 596 insertions(+), 5 deletions(-) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java create mode 100644 jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 5b5f65bda22..9de8c5384ef 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -40,6 +40,7 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; @@ -178,6 +179,13 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return false; } + @Override + public boolean onPushPromise(PushPromiseFrame frame) + { + // TODO + return false; + } + @Override public boolean onPing(PingFrame frame) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java new file mode 100644 index 00000000000..47dc39cbdfc --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java @@ -0,0 +1,51 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import org.eclipse.jetty.http2.hpack.MetaData; + +public class PushPromiseFrame extends Frame +{ + private final int streamId; + private final int promisedStreamId; + private final MetaData metaData; + + public PushPromiseFrame(int streamId, int promisedStreamId, MetaData metaData) + { + super(FrameType.PUSH_PROMISE); + this.streamId = streamId; + this.promisedStreamId = promisedStreamId; + this.metaData = metaData; + } + + public int getStreamId() + { + return streamId; + } + + public int getPromisedStreamId() + { + return promisedStreamId; + } + + public MetaData getMetaData() + { + return metaData; + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 21d98af10c5..a4a3591540f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -49,7 +49,7 @@ public class Generator this.generators[FrameType.PRIORITY.getType()] = new PriorityGenerator(headerGenerator); this.generators[FrameType.RST_STREAM.getType()] = new ResetGenerator(headerGenerator); this.generators[FrameType.SETTINGS.getType()] = new SettingsGenerator(headerGenerator); - this.generators[FrameType.PUSH_PROMISE.getType()] = null; // TODO + this.generators[FrameType.PUSH_PROMISE.getType()] = new PushPromiseGenerator(headerGenerator, encoder); this.generators[FrameType.PING.getType()] = new PingGenerator(headerGenerator); this.generators[FrameType.GO_AWAY.getType()] = new GoAwayGenerator(headerGenerator); this.generators[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateGenerator(headerGenerator); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index d3671407736..1229fdc17ef 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -43,10 +43,10 @@ public class HeadersGenerator extends FrameGenerator public void generate(ByteBufferPool.Lease lease, Frame frame) { HeadersFrame headersFrame = (HeadersFrame)frame; - generate(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream()); + generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream()); } - private void generate(ByteBufferPool.Lease lease, int streamId, MetaData metaData, boolean contentFollows) + public void generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, boolean contentFollows) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java new file mode 100644 index 00000000000..41eeb7e6bb3 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -0,0 +1,55 @@ +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.http2.hpack.HpackEncoder; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; + +public class PushPromiseGenerator extends FrameGenerator +{ + private final HpackEncoder encoder; + + public PushPromiseGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder) + { + super(headerGenerator); + this.encoder = encoder; + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame) + { + PushPromiseFrame pushPromiseFrame = (PushPromiseFrame)frame; + generatePushPromise(lease, pushPromiseFrame.getStreamId(), pushPromiseFrame.getPromisedStreamId(), pushPromiseFrame.getMetaData()); + } + + public void generatePushPromise(ByteBufferPool.Lease lease, int streamId, int promisedStreamId, MetaData metaData) + { + if (streamId < 0) + throw new IllegalArgumentException("Invalid stream id: " + streamId); + if (promisedStreamId < 0) + throw new IllegalArgumentException("Invalid promised stream id: " + promisedStreamId); + + encoder.encode(metaData, lease); + + long length = lease.getTotalLength(); + if (length > Frame.MAX_LENGTH) + throw new IllegalArgumentException("Invalid headers, too big"); + + // Space for the promised streamId. + length += 4; + + int flags = Flag.END_HEADERS; + + ByteBuffer header = generateHeader(lease, FrameType.PUSH_PROMISE, (int)length, flags, streamId); + header.putInt(promisedStreamId); + + BufferUtil.flipToFlush(header, 0); + lease.prepend(header, true); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 51fcfda05b9..016ebf31ba5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; @@ -148,6 +149,19 @@ public abstract class BodyParser } } + protected boolean notifyPushPromise(PushPromiseFrame frame) + { + try + { + return listener.onPushPromise(frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return false; + } + } + protected boolean notifyPing(PingFrame frame) { try diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 88cd6a9498f..dbccae1f61e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; @@ -56,7 +57,7 @@ public class Parser bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); bodyParsers[FrameType.SETTINGS.getType()] = new SettingsBodyParser(headerParser, listener); - bodyParsers[FrameType.PUSH_PROMISE.getType()] = null; // TODO + bodyParsers[FrameType.PUSH_PROMISE.getType()] = new PushPromiseBodyParser(headerParser, listener, headerBlockParser); bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener); bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener); bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener); @@ -172,6 +173,8 @@ public class Parser public boolean onSettings(SettingsFrame frame); + public boolean onPushPromise(PushPromiseFrame frame); + public boolean onPing(PingFrame frame); public boolean onGoAway(GoAwayFrame frame); @@ -212,6 +215,12 @@ public class Parser return false; } + @Override + public boolean onPushPromise(PushPromiseFrame frame) + { + return false; + } + @Override public boolean onPing(PingFrame frame) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java new file mode 100644 index 00000000000..87074ae6282 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -0,0 +1,190 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.http2.hpack.MetaData; + +public class PushPromiseBodyParser extends BodyParser +{ + private final HeaderBlockParser headerBlockParser; + private State state = State.PREPARE; + private int cursor; + private int length; + private int paddingLength; + private int streamId; + + public PushPromiseBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser) + { + super(headerParser, listener); + this.headerBlockParser = headerBlockParser; + } + + private void reset() + { + state = State.PREPARE; + cursor = 0; + length = 0; + paddingLength = 0; + streamId = 0; + } + + @Override + public Result parse(ByteBuffer buffer) + { + boolean loop = false; + while (buffer.hasRemaining() || loop) + { + switch (state) + { + case PREPARE: + { + // SPEC: wrong streamId is treated as connection error. + if (getStreamId() == 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); + } + length = getBodyLength(); + if (isPaddingHigh()) + { + state = State.PADDING_HIGH; + } + else if (isPaddingLow()) + { + state = State.PADDING_LOW; + } + else + { + state = State.STREAM_ID; + } + break; + } + case PADDING_HIGH: + { + paddingLength = (buffer.get() & 0xFF) << 8; + --length; + state = State.PADDING_LOW; + if (length < 1 + 256) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame_padding"); + } + break; + } + case PADDING_LOW: + { + paddingLength += buffer.get() & 0xFF; + --length; + length -= paddingLength; + state = State.STREAM_ID; + loop = length == 0; + if (length < 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame_padding"); + } + break; + } + case STREAM_ID: + { + if (buffer.remaining() >= 4) + { + streamId = buffer.getInt(); + streamId &= 0x7F_FF_FF_FF; + length -= 4; + state = State.HEADERS; + if (length < 1) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); + } + } + else + { + state = State.STREAM_ID_BYTES; + cursor = 4; + } + break; + } + case STREAM_ID_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + streamId += currByte << (8 * cursor); + --length; + if (cursor > 0 && length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); + } + if (cursor == 0) + { + streamId &= 0x7F_FF_FF_FF; + state = State.HEADERS; + if (length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); + } + } + break; + } + case HEADERS: + { + MetaData metaData = headerBlockParser.parse(buffer, length); + if (metaData != null) + { + state = State.PADDING; + loop = paddingLength == 0; + if (onPushPromise(streamId, metaData)) + { + return Result.ASYNC; + } + } + break; + } + case PADDING: + { + int size = Math.min(buffer.remaining(), paddingLength); + buffer.position(buffer.position() + size); + paddingLength -= size; + if (paddingLength == 0) + { + reset(); + return Result.COMPLETE; + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return Result.PENDING; + } + + private boolean onPushPromise(int streamId, MetaData metaData) + { + PushPromiseFrame frame = new PushPromiseFrame(getStreamId(), streamId, metaData); + return notifyPushPromise(frame); + } + + private enum State + { + PREPARE, PADDING_HIGH, PADDING_LOW, STREAM_ID, STREAM_ID_BYTES, HEADERS, PADDING + } +} diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 0ec83ca16ec..6e2cefcba7a 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -18,17 +18,131 @@ package org.eclipse.jetty.http2.frames; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http2.generator.HeaderGenerator; +import org.eclipse.jetty.http2.generator.HeadersGenerator; +import org.eclipse.jetty.http2.hpack.HpackEncoder; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; public class HeadersGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + @Ignore @Test public void testGenerateParse() throws Exception { - // TODO + HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder()); + + int streamId = 13; + HttpFields fields = new HttpFields(); + fields.put("Accept", "text/html"); + fields.put("User-Agent", "Jetty"); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + + // Iterate a few times to be sure generator and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateHeaders(lease, streamId, metaData, false); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onHeaders(HeadersFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + + Assert.assertEquals(1, frames.size()); + HeadersFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertTrue(frame.isEndStream()); + MetaData.Request request = (MetaData.Request)frame.getMetaData(); + Assert.assertSame(metaData.getScheme(), request.getScheme()); + Assert.assertEquals(metaData.getMethod(), request.getMethod()); + Assert.assertEquals(metaData.getAuthority(), request.getAuthority()); + Assert.assertEquals(metaData.getHost(), request.getHost()); + Assert.assertEquals(metaData.getPort(), request.getPort()); + Assert.assertEquals(metaData.getPath(), request.getPath()); + for (int j = 0; j < fields.size(); ++j) + { + HttpField field = fields.getField(j); + Assert.assertTrue(request.getFields().contains(field)); + } + } + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder()); + + int streamId = 13; + HttpFields fields = new HttpFields(); + fields.put("Accept", "text/html"); + fields.put("User-Agent", "Jetty"); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + + final List frames = new ArrayList<>(); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateHeaders(lease, streamId, metaData, false); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onHeaders(HeadersFrame frame) + { + frames.add(frame); + return false; + } + }); + + for (ByteBuffer buffer : lease.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(1, frames.size()); + HeadersFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertTrue(frame.isEndStream()); + MetaData.Request request = (MetaData.Request)frame.getMetaData(); + Assert.assertSame(metaData.getScheme(), request.getScheme()); + Assert.assertEquals(metaData.getMethod(), request.getMethod()); + Assert.assertEquals(metaData.getAuthority(), request.getAuthority()); + Assert.assertEquals(metaData.getHost(), request.getHost()); + Assert.assertEquals(metaData.getPort(), request.getPort()); + Assert.assertEquals(metaData.getPath(), request.getPath()); + for (int j = 0; j < fields.size(); ++j) + { + HttpField field = fields.getField(j); + Assert.assertTrue(request.getFields().contains(field)); + } } } diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java new file mode 100644 index 00000000000..ebbf88fc56b --- /dev/null +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -0,0 +1,150 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http2.generator.HeaderGenerator; +import org.eclipse.jetty.http2.generator.PushPromiseGenerator; +import org.eclipse.jetty.http2.hpack.HpackEncoder; +import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +public class PushPromiseGenerateParseTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + @Ignore + @Test + public void testGenerateParse() throws Exception + { + PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder()); + + int streamId = 13; + int promisedStreamId = 17; + HttpFields fields = new HttpFields(); + fields.put("Accept", "text/html"); + fields.put("User-Agent", "Jetty"); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + + // Iterate a few times to be sure generator and parser are properly reset. + final List frames = new ArrayList<>(); + for (int i = 0; i < 2; ++i) + { + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePushPromise(lease, streamId, promisedStreamId, metaData); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onPushPromise(PushPromiseFrame frame) + { + frames.add(frame); + return false; + } + }); + + frames.clear(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + + Assert.assertEquals(1, frames.size()); + PushPromiseFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertEquals(promisedStreamId, frame.getPromisedStreamId()); + MetaData.Request request = (MetaData.Request)frame.getMetaData(); + Assert.assertSame(metaData.getScheme(), request.getScheme()); + Assert.assertEquals(metaData.getMethod(), request.getMethod()); + Assert.assertEquals(metaData.getAuthority(), request.getAuthority()); + Assert.assertEquals(metaData.getHost(), request.getHost()); + Assert.assertEquals(metaData.getPort(), request.getPort()); + Assert.assertEquals(metaData.getPath(), request.getPath()); + for (int j = 0; j < fields.size(); ++j) + { + HttpField field = fields.getField(j); + Assert.assertTrue(request.getFields().contains(field)); + } + } + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder()); + + int streamId = 13; + int promisedStreamId = 17; + HttpFields fields = new HttpFields(); + fields.put("Accept", "text/html"); + fields.put("User-Agent", "Jetty"); + MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + + final List frames = new ArrayList<>(); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePushPromise(lease, streamId, promisedStreamId, metaData); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onPushPromise(PushPromiseFrame frame) + { + frames.add(frame); + return false; + } + }); + + for (ByteBuffer buffer : lease.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } + } + + Assert.assertEquals(1, frames.size()); + PushPromiseFrame frame = frames.get(0); + Assert.assertEquals(streamId, frame.getStreamId()); + Assert.assertEquals(promisedStreamId, frame.getPromisedStreamId()); + MetaData.Request request = (MetaData.Request)frame.getMetaData(); + Assert.assertSame(metaData.getScheme(), request.getScheme()); + Assert.assertEquals(metaData.getMethod(), request.getMethod()); + Assert.assertEquals(metaData.getAuthority(), request.getAuthority()); + Assert.assertEquals(metaData.getHost(), request.getHost()); + Assert.assertEquals(metaData.getPort(), request.getPort()); + Assert.assertEquals(metaData.getPath(), request.getPath()); + for (int j = 0; j < fields.size(); ++j) + { + HttpField field = fields.getField(j); + Assert.assertTrue(request.getFields().contains(field)); + } + } +} From 9af8eb9fa7592661ad33ef59647912b524a1ce79 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 15:45:10 +0200 Subject: [PATCH 084/269] Replying to SETTINGS frame as requested by the specification. --- .../src/main/java/org/eclipse/jetty/http2/HTTP2Session.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 9de8c5384ef..ee949e45949 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -176,6 +177,10 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } // TODO: handle other settings notifySettings(this, frame); + + // SPEC: SETTINGS frame MUST be replied. + SettingsFrame reply = new SettingsFrame(Collections.emptyMap(), true); + settings(reply, disconnectCallback); return false; } From e6e68c55578c805d7ebbbfe6c336b51635cdb78e Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 16:09:47 +0200 Subject: [PATCH 085/269] Added license header. --- .../http2/generator/PushPromiseGenerator.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index 41eeb7e6bb3..38ef5b38de2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -1,3 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; From a6329451a139608f23415949ae2da12752210fc8 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 18:15:13 +0200 Subject: [PATCH 086/269] Updated HTTP2 modules to be included in the distribution. --- jetty-distribution/pom.xml | 20 +++++- jetty-http2/http2-server/pom.xml | 17 ++++++ .../src/main/config/etc/jetty-http2.xml | 61 +++++++++++++++++++ .../src/main/config/modules/http2.mod | 23 +++++++ .../server/HTTP2ServerConnectionFactory.java | 3 +- 5 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml create mode 100644 jetty-http2/http2-server/src/main/config/modules/http2.mod diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index dcac04f87ba..2decd3463d7 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -301,7 +301,7 @@ org.eclipse.jetty - org.eclipse.jetty.orbit,org.eclipse.jetty.spdy,org.eclipse.jetty.websocket,org.eclipse.jetty.fcgi,org.eclipse.jetty.toolchain,org.apache.taglibs + org.eclipse.jetty.orbit,org.eclipse.jetty.http2,org.eclipse.jetty.spdy,org.eclipse.jetty.websocket,org.eclipse.jetty.fcgi,org.eclipse.jetty.toolchain,org.apache.taglibs jetty-all,jetty-jsp,apache-jsp,jetty-start,jetty-monitor,jetty-spring jar ${assembly-directory}/lib @@ -320,6 +320,19 @@ ${assembly-directory}/lib/websocket + + copy-lib-http2-deps + generate-resources + + copy-dependencies + + + org.eclipse.jetty.http2 + http2-hpack,http2-common,http2-server + jar + ${assembly-directory}/lib/http2 + + copy-lib-fcgi-deps generate-resources @@ -805,6 +818,11 @@ jetty-rewrite ${project.version} + + org.eclipse.jetty.http2 + http2-server + ${project.version} + org.eclipse.jetty.spdy spdy-core diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index 3141e017a46..c6c2b7b07aa 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -14,6 +14,23 @@ + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + config + + + + + org.apache.felix maven-bundle-plugin diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml new file mode 100644 index 00000000000..038f3d1371a --- /dev/null +++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-http2/http2-server/src/main/config/modules/http2.mod b/jetty-http2/http2-server/src/main/config/modules/http2.mod new file mode 100644 index 00000000000..a327ec6aade --- /dev/null +++ b/jetty-http2/http2-server/src/main/config/modules/http2.mod @@ -0,0 +1,23 @@ +# +# HTTP2 Support Module +# + +[depend] +ssl +protonego + +[lib] +lib/http2/*.jar + +[xml] +etc/jetty-ssl.xml +etc/jetty-http2.xml + +[ini-template] +## HTTP2 Configuration + +# Port for HTTP2 connections +http2.port=8443 + +# HTTP2 idle timeout in milliseconds +http2.timeout=30000 diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 5aa169481ca..61ccdce5583 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -32,6 +32,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -42,7 +43,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF private final HttpConfiguration httpConfiguration; - public HTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration) + public HTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration) { this.httpConfiguration = httpConfiguration; } From 1d2690ed11f2458173d6ffdaf15ac7aa3b0344a8 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 21:21:43 +0200 Subject: [PATCH 087/269] Removed unneeded reference to jetty-ssl.xml, implicitly referenced transitively by the dependency on the ssl module. --- jetty-http2/http2-server/src/main/config/modules/http2.mod | 1 - 1 file changed, 1 deletion(-) diff --git a/jetty-http2/http2-server/src/main/config/modules/http2.mod b/jetty-http2/http2-server/src/main/config/modules/http2.mod index a327ec6aade..b0d4bc8910a 100644 --- a/jetty-http2/http2-server/src/main/config/modules/http2.mod +++ b/jetty-http2/http2-server/src/main/config/modules/http2.mod @@ -10,7 +10,6 @@ protonego lib/http2/*.jar [xml] -etc/jetty-ssl.xml etc/jetty-http2.xml [ini-template] From 334db9fe72facc8b0a9823b02e2a7c42e2435dd5 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 21:33:03 +0200 Subject: [PATCH 088/269] Updated version to 9.3.0-SNAPSHOT. --- aggregates/jetty-all/pom.xml | 2 +- apache-jsp/pom.xml | 2 +- apache-jstl/pom.xml | 2 +- examples/async-rest/async-rest-jar/pom.xml | 2 +- examples/async-rest/async-rest-webapp/pom.xml | 2 +- examples/async-rest/pom.xml | 2 +- examples/embedded/pom.xml | 2 +- examples/pom.xml | 2 +- jetty-alpn/jetty-alpn-client/pom.xml | 2 +- jetty-alpn/jetty-alpn-server/pom.xml | 2 +- jetty-alpn/pom.xml | 2 +- jetty-annotations/pom.xml | 2 +- jetty-ant/pom.xml | 2 +- jetty-client/pom.xml | 2 +- jetty-continuation/pom.xml | 2 +- jetty-deploy/pom.xml | 2 +- jetty-distribution/pom.xml | 2 +- jetty-fcgi/fcgi-client/pom.xml | 2 +- jetty-fcgi/fcgi-server/pom.xml | 2 +- jetty-fcgi/pom.xml | 2 +- jetty-http-spi/pom.xml | 2 +- jetty-http/pom.xml | 2 +- jetty-http2/http2-client/pom.xml | 2 +- jetty-http2/http2-common/pom.xml | 2 +- jetty-http2/http2-hpack/pom.xml | 2 +- jetty-http2/http2-server/pom.xml | 2 +- jetty-http2/pom.xml | 2 +- jetty-io/pom.xml | 2 +- jetty-jaas/pom.xml | 2 +- jetty-jaspi/pom.xml | 2 +- jetty-jmx/pom.xml | 2 +- jetty-jndi/pom.xml | 2 +- jetty-jsp/pom.xml | 2 +- jetty-jspc-maven-plugin/pom.xml | 2 +- jetty-maven-plugin/pom.xml | 2 +- jetty-monitor/pom.xml | 2 +- jetty-nosql/pom.xml | 2 +- jetty-npn/jetty-npn-client/pom.xml | 2 +- jetty-npn/jetty-npn-server/pom.xml | 2 +- jetty-npn/pom.xml | 2 +- jetty-osgi/jetty-osgi-alpn/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot-jsp/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot-warurl/pom.xml | 2 +- jetty-osgi/jetty-osgi-boot/pom.xml | 2 +- jetty-osgi/jetty-osgi-httpservice/pom.xml | 2 +- jetty-osgi/jetty-osgi-npn/pom.xml | 2 +- jetty-osgi/pom.xml | 2 +- jetty-osgi/test-jetty-osgi-context/pom.xml | 2 +- jetty-osgi/test-jetty-osgi-webapp/pom.xml | 2 +- jetty-osgi/test-jetty-osgi/pom.xml | 2 +- jetty-plus/pom.xml | 2 +- jetty-proxy/pom.xml | 2 +- jetty-quickstart/pom.xml | 2 +- jetty-rewrite/pom.xml | 2 +- jetty-runner/pom.xml | 2 +- jetty-security/pom.xml | 2 +- jetty-server/pom.xml | 2 +- jetty-servlet/pom.xml | 2 +- jetty-servlets/pom.xml | 2 +- jetty-spdy/pom.xml | 2 +- jetty-spdy/spdy-alpn-tests/pom.xml | 2 +- jetty-spdy/spdy-client/pom.xml | 2 +- jetty-spdy/spdy-core/pom.xml | 2 +- jetty-spdy/spdy-example-webapp/pom.xml | 2 +- jetty-spdy/spdy-http-client-transport/pom.xml | 2 +- jetty-spdy/spdy-http-common/pom.xml | 2 +- jetty-spdy/spdy-http-server/pom.xml | 2 +- jetty-spdy/spdy-npn-tests/pom.xml | 2 +- jetty-spdy/spdy-server/pom.xml | 2 +- jetty-spring/pom.xml | 2 +- jetty-start/pom.xml | 2 +- jetty-util-ajax/pom.xml | 2 +- jetty-util/pom.xml | 2 +- jetty-webapp/pom.xml | 2 +- jetty-websocket/javax-websocket-client-impl/pom.xml | 2 +- jetty-websocket/javax-websocket-server-impl/pom.xml | 2 +- jetty-websocket/pom.xml | 2 +- jetty-websocket/websocket-api/pom.xml | 2 +- jetty-websocket/websocket-client/pom.xml | 2 +- jetty-websocket/websocket-common/pom.xml | 2 +- jetty-websocket/websocket-server/pom.xml | 2 +- jetty-websocket/websocket-servlet/pom.xml | 2 +- jetty-xml/pom.xml | 2 +- pom.xml | 2 +- tests/pom.xml | 2 +- tests/test-continuation/pom.xml | 2 +- tests/test-integration/pom.xml | 2 +- tests/test-loginservice/pom.xml | 2 +- tests/test-sessions/pom.xml | 2 +- tests/test-sessions/test-hash-sessions/pom.xml | 2 +- tests/test-sessions/test-jdbc-sessions/pom.xml | 2 +- tests/test-sessions/test-sessions-common/pom.xml | 2 +- tests/test-webapps/pom.xml | 2 +- tests/test-webapps/test-jaas-webapp/pom.xml | 2 +- tests/test-webapps/test-jetty-webapp/pom.xml | 2 +- tests/test-webapps/test-jndi-webapp/pom.xml | 2 +- tests/test-webapps/test-mock-resources/pom.xml | 2 +- tests/test-webapps/test-proxy-webapp/pom.xml | 2 +- tests/test-webapps/test-servlet-spec/pom.xml | 2 +- .../test-servlet-spec/test-container-initializer/pom.xml | 2 +- tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml | 2 +- tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml | 2 +- tests/test-webapps/test-webapp-rfc2616/pom.xml | 2 +- 103 files changed, 103 insertions(+), 103 deletions(-) diff --git a/aggregates/jetty-all/pom.xml b/aggregates/jetty-all/pom.xml index cb8ffa0df8f..7f054c24fd3 100644 --- a/aggregates/jetty-all/pom.xml +++ b/aggregates/jetty-all/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/apache-jsp/pom.xml b/apache-jsp/pom.xml index 17e94713700..8799749c513 100644 --- a/apache-jsp/pom.xml +++ b/apache-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 apache-jsp diff --git a/apache-jstl/pom.xml b/apache-jstl/pom.xml index 9782ee66cdc..93628bf57dd 100644 --- a/apache-jstl/pom.xml +++ b/apache-jstl/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 apache-jstl diff --git a/examples/async-rest/async-rest-jar/pom.xml b/examples/async-rest/async-rest-jar/pom.xml index e10ed25ed3c..e9d5220edc0 100644 --- a/examples/async-rest/async-rest-jar/pom.xml +++ b/examples/async-rest/async-rest-jar/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 org.eclipse.jetty.example-async-rest diff --git a/examples/async-rest/async-rest-webapp/pom.xml b/examples/async-rest/async-rest-webapp/pom.xml index 3b0adf80937..f12a5ba66ae 100644 --- a/examples/async-rest/async-rest-webapp/pom.xml +++ b/examples/async-rest/async-rest-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 org.eclipse.jetty.example-async-rest diff --git a/examples/async-rest/pom.xml b/examples/async-rest/pom.xml index 4921cea51a4..d7ccc24b6a4 100644 --- a/examples/async-rest/pom.xml +++ b/examples/async-rest/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.examples examples-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/examples/embedded/pom.xml b/examples/embedded/pom.xml index 8441c8f65a4..d66bcd882a2 100644 --- a/examples/embedded/pom.xml +++ b/examples/embedded/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.examples examples-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/examples/pom.xml b/examples/pom.xml index c2afbed3bb5..613daa27629 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml org.eclipse.jetty.examples diff --git a/jetty-alpn/jetty-alpn-client/pom.xml b/jetty-alpn/jetty-alpn-client/pom.xml index 1f8b0b960e6..63c74b64bee 100644 --- a/jetty-alpn/jetty-alpn-client/pom.xml +++ b/jetty-alpn/jetty-alpn-client/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-alpn-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-alpn-client diff --git a/jetty-alpn/jetty-alpn-server/pom.xml b/jetty-alpn/jetty-alpn-server/pom.xml index 537fc2177ba..ad0b78f7185 100644 --- a/jetty-alpn/jetty-alpn-server/pom.xml +++ b/jetty-alpn/jetty-alpn-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-alpn-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-alpn-server diff --git a/jetty-alpn/pom.xml b/jetty-alpn/pom.xml index c5403fcc4bd..2a758b18585 100644 --- a/jetty-alpn/pom.xml +++ b/jetty-alpn/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-alpn-parent diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index 4fe968973e1..31a1cf92dde 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-annotations diff --git a/jetty-ant/pom.xml b/jetty-ant/pom.xml index d4233cf64d5..300b5013dbb 100644 --- a/jetty-ant/pom.xml +++ b/jetty-ant/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-ant diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index 62303365833..b0d773c79e3 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index 5d1fab51c6e..5fd2ee0a3f3 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-continuation diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index bff6397e2f4..9a843df37e0 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-deploy diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index 2decd3463d7..83cb5f7d1c9 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT jetty-distribution Jetty :: Distribution Assemblies diff --git a/jetty-fcgi/fcgi-client/pom.xml b/jetty-fcgi/fcgi-client/pom.xml index 2f460ee7f35..d63324e175b 100644 --- a/jetty-fcgi/fcgi-client/pom.xml +++ b/jetty-fcgi/fcgi-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-fcgi/fcgi-server/pom.xml b/jetty-fcgi/fcgi-server/pom.xml index 5117cdd7ee8..1c57cc5c96b 100644 --- a/jetty-fcgi/fcgi-server/pom.xml +++ b/jetty-fcgi/fcgi-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-fcgi/pom.xml b/jetty-fcgi/pom.xml index 9df08800c4e..e5c936665ce 100644 --- a/jetty-fcgi/pom.xml +++ b/jetty-fcgi/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml index 05938667a22..9706bdde775 100644 --- a/jetty-http-spi/pom.xml +++ b/jetty-http-spi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-http-spi diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 8f007daf70d..d7c288ca103 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-http diff --git a/jetty-http2/http2-client/pom.xml b/jetty-http2/http2-client/pom.xml index 42ef50da4ed..a509d586ea1 100644 --- a/jetty-http2/http2-client/pom.xml +++ b/jetty-http2/http2-client/pom.xml @@ -5,7 +5,7 @@ org.eclipse.jetty.http2 http2-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-http2/http2-common/pom.xml b/jetty-http2/http2-common/pom.xml index 4b150f04e99..2a8baffa5cc 100644 --- a/jetty-http2/http2-common/pom.xml +++ b/jetty-http2/http2-common/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-http2/http2-hpack/pom.xml b/jetty-http2/http2-hpack/pom.xml index 26866091022..8b7a7fe8f1c 100644 --- a/jetty-http2/http2-hpack/pom.xml +++ b/jetty-http2/http2-hpack/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index c6c2b7b07aa..0bf5ecc0cd7 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -5,7 +5,7 @@ org.eclipse.jetty.http2 http2-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index 6ced51c6dfd..fb706303761 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index d54dd4289a5..3b94edde47d 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -2,7 +2,7 @@ jetty-project org.eclipse.jetty - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-io diff --git a/jetty-jaas/pom.xml b/jetty-jaas/pom.xml index ea72da470e1..04e827fbbe0 100644 --- a/jetty-jaas/pom.xml +++ b/jetty-jaas/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-jaas diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index 3def5f7276d..37b062b7688 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-jaspi diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index 7f73d687589..e56bdadcf91 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-jmx diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index 91155fece36..70a88f0c7f6 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-jndi diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml index e38af5c4976..9c279dcc714 100644 --- a/jetty-jsp/pom.xml +++ b/jetty-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-jsp diff --git a/jetty-jspc-maven-plugin/pom.xml b/jetty-jspc-maven-plugin/pom.xml index cdbdb7344c3..015d5bf1096 100644 --- a/jetty-jspc-maven-plugin/pom.xml +++ b/jetty-jspc-maven-plugin/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-jspc-maven-plugin diff --git a/jetty-maven-plugin/pom.xml b/jetty-maven-plugin/pom.xml index f9ad5fc4d62..e5c9c464559 100644 --- a/jetty-maven-plugin/pom.xml +++ b/jetty-maven-plugin/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-maven-plugin diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index d6e5fac5805..034b9e4d7eb 100644 --- a/jetty-monitor/pom.xml +++ b/jetty-monitor/pom.xml @@ -19,7 +19,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-monitor diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index a6ba6a6cec5..f283899a5ba 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-nosql diff --git a/jetty-npn/jetty-npn-client/pom.xml b/jetty-npn/jetty-npn-client/pom.xml index bf9b4564225..26aab23bfad 100644 --- a/jetty-npn/jetty-npn-client/pom.xml +++ b/jetty-npn/jetty-npn-client/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-npn-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-npn-client diff --git a/jetty-npn/jetty-npn-server/pom.xml b/jetty-npn/jetty-npn-server/pom.xml index 9554de4f0d6..a2d18dff8da 100644 --- a/jetty-npn/jetty-npn-server/pom.xml +++ b/jetty-npn/jetty-npn-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-npn-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-npn-server diff --git a/jetty-npn/pom.xml b/jetty-npn/pom.xml index 163f0c7439a..da0f55fe1e8 100644 --- a/jetty-npn/pom.xml +++ b/jetty-npn/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-npn-parent diff --git a/jetty-osgi/jetty-osgi-alpn/pom.xml b/jetty-osgi/jetty-osgi-alpn/pom.xml index 001c3349ede..b863f69f663 100644 --- a/jetty-osgi/jetty-osgi-alpn/pom.xml +++ b/jetty-osgi/jetty-osgi-alpn/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-osgi-alpn diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index 9aac5e0d75a..a61cdeecab8 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-osgi-boot-jsp diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index 88049e37084..f45907d72bf 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index e34518fb9de..a5b8453e7c4 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-osgi-boot diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml index 660aeb6bae8..dc840b4fd80 100644 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml +++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-httpservice diff --git a/jetty-osgi/jetty-osgi-npn/pom.xml b/jetty-osgi/jetty-osgi-npn/pom.xml index 3319e6f753d..a19818e04ae 100644 --- a/jetty-osgi/jetty-osgi-npn/pom.xml +++ b/jetty-osgi/jetty-osgi-npn/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-osgi-npn diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index 25153de45d7..02bd25f8d1e 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT org.eclipse.jetty.osgi jetty-osgi-project diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml index d7bde5105ab..af63bd1a953 100644 --- a/jetty-osgi/test-jetty-osgi-context/pom.xml +++ b/jetty-osgi/test-jetty-osgi-context/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 test-jetty-osgi-context diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml index ef98098982f..4511aed2a61 100644 --- a/jetty-osgi/test-jetty-osgi-webapp/pom.xml +++ b/jetty-osgi/test-jetty-osgi-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index 03938478c9d..191d0fa41f6 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index 79852c47586..c7eadc372a5 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-plus diff --git a/jetty-proxy/pom.xml b/jetty-proxy/pom.xml index feaff50afc6..d2550a20fa0 100644 --- a/jetty-proxy/pom.xml +++ b/jetty-proxy/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-proxy diff --git a/jetty-quickstart/pom.xml b/jetty-quickstart/pom.xml index 69dde04d135..a6f3314e4bd 100644 --- a/jetty-quickstart/pom.xml +++ b/jetty-quickstart/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 org.eclipse.jetty diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index 0908ac2ca19..578009f528c 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-rewrite diff --git a/jetty-runner/pom.xml b/jetty-runner/pom.xml index 57409ec4ded..7c7350d2cd9 100644 --- a/jetty-runner/pom.xml +++ b/jetty-runner/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-runner diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index 4e946580c63..e3361f53c75 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-security diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index e8d6810553c..33d50c6ef5f 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-server diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index 3428ef0ef4d..f5a3b528411 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-servlet diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index 9b87556856e..4acf0c8f55a 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-servlets diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index 5c9aa6f5f3c..7e1bdf0db8b 100644 --- a/jetty-spdy/pom.xml +++ b/jetty-spdy/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-alpn-tests/pom.xml b/jetty-spdy/spdy-alpn-tests/pom.xml index 3cb7f0103d5..0d02b5054c7 100644 --- a/jetty-spdy/spdy-alpn-tests/pom.xml +++ b/jetty-spdy/spdy-alpn-tests/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml index b883aeb72c7..3fe70e3c710 100644 --- a/jetty-spdy/spdy-client/pom.xml +++ b/jetty-spdy/spdy-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml index 4454b275d2f..047b1799203 100644 --- a/jetty-spdy/spdy-core/pom.xml +++ b/jetty-spdy/spdy-core/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml index 2ac644482bc..4a25712d6ad 100644 --- a/jetty-spdy/spdy-example-webapp/pom.xml +++ b/jetty-spdy/spdy-example-webapp/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 spdy-example-webapp diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml index 19fbdd07a5c..2562ac25871 100644 --- a/jetty-spdy/spdy-http-client-transport/pom.xml +++ b/jetty-spdy/spdy-http-client-transport/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-http-common/pom.xml b/jetty-spdy/spdy-http-common/pom.xml index d98cbac88e2..d9b607888b3 100644 --- a/jetty-spdy/spdy-http-common/pom.xml +++ b/jetty-spdy/spdy-http-common/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml index fda057be235..f5a6373fa03 100644 --- a/jetty-spdy/spdy-http-server/pom.xml +++ b/jetty-spdy/spdy-http-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 spdy-http-server diff --git a/jetty-spdy/spdy-npn-tests/pom.xml b/jetty-spdy/spdy-npn-tests/pom.xml index 60782fd0048..f11d9a0e6d2 100644 --- a/jetty-spdy/spdy-npn-tests/pom.xml +++ b/jetty-spdy/spdy-npn-tests/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index e4bc43e1be0..83e98333509 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.spdy spdy-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-spring/pom.xml b/jetty-spring/pom.xml index 849aa18ecc2..0adc885f03c 100644 --- a/jetty-spring/pom.xml +++ b/jetty-spring/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-spring diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 6da601b807c..75cc0e4e3af 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-start diff --git a/jetty-util-ajax/pom.xml b/jetty-util-ajax/pom.xml index 7cfc7d725fc..a0ad0e84109 100644 --- a/jetty-util-ajax/pom.xml +++ b/jetty-util-ajax/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-util-ajax diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index 3eb4e266e9a..f0a4e25a188 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-util diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index 50f383d9815..93b646dda5d 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-webapp diff --git a/jetty-websocket/javax-websocket-client-impl/pom.xml b/jetty-websocket/javax-websocket-client-impl/pom.xml index b322d3fe8fe..f6d2375e4f0 100644 --- a/jetty-websocket/javax-websocket-client-impl/pom.xml +++ b/jetty-websocket/javax-websocket-client-impl/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/javax-websocket-server-impl/pom.xml b/jetty-websocket/javax-websocket-server-impl/pom.xml index 71e3bfcdf74..745cac24834 100644 --- a/jetty-websocket/javax-websocket-server-impl/pom.xml +++ b/jetty-websocket/javax-websocket-server-impl/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 4d65f40246a..941a7900c41 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-api/pom.xml b/jetty-websocket/websocket-api/pom.xml index 628d7cdd8a4..2c078b8b196 100644 --- a/jetty-websocket/websocket-api/pom.xml +++ b/jetty-websocket/websocket-api/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-client/pom.xml b/jetty-websocket/websocket-client/pom.xml index a0b91e6f6f1..b09cd38407b 100644 --- a/jetty-websocket/websocket-client/pom.xml +++ b/jetty-websocket/websocket-client/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-common/pom.xml b/jetty-websocket/websocket-common/pom.xml index 98bdd5a68ae..de1da484992 100644 --- a/jetty-websocket/websocket-common/pom.xml +++ b/jetty-websocket/websocket-common/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-server/pom.xml b/jetty-websocket/websocket-server/pom.xml index 5f55cccf418..e6338d50d63 100644 --- a/jetty-websocket/websocket-server/pom.xml +++ b/jetty-websocket/websocket-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-websocket/websocket-servlet/pom.xml b/jetty-websocket/websocket-servlet/pom.xml index 34126478ea3..97bf9cff6c6 100644 --- a/jetty-websocket/websocket-servlet/pom.xml +++ b/jetty-websocket/websocket-servlet/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index 70a6487a960..6d77d412758 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 jetty-xml diff --git a/pom.xml b/pom.xml index 9dd59003f0e..2db2e3c0d9b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 22 jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT Jetty :: Project http://www.eclipse.org/jetty pom diff --git a/tests/pom.xml b/tests/pom.xml index e2398f4638d..6af4606662d 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty jetty-project - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml org.eclipse.jetty.tests diff --git a/tests/test-continuation/pom.xml b/tests/test-continuation/pom.xml index 2a0e01889e3..1f7cb0b0450 100644 --- a/tests/test-continuation/pom.xml +++ b/tests/test-continuation/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests tests-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml index d6a5433bc5c..e08d8585f5d 100644 --- a/tests/test-integration/pom.xml +++ b/tests/test-integration/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests tests-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT 4.0.0 test-integration diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml index 9d039866f16..88d2e6783a2 100644 --- a/tests/test-loginservice/pom.xml +++ b/tests/test-loginservice/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-loginservice Jetty Tests :: Login Service diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml index 697a0ff9b9f..67fb24055ed 100644 --- a/tests/test-sessions/pom.xml +++ b/tests/test-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-sessions-parent Jetty Tests :: Sessions :: Parent diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index 88511cfbfef..d03667ed5e4 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-hash-sessions Jetty Tests :: Sessions :: Hash diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 0f501679a1e..39f905d0e88 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-jdbc-sessions Jetty Tests :: Sessions :: JDBC diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index 3c9cf038d42..e608d5d357e 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-sessions-common Jetty Tests :: Sessions :: Common diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index 72ffebae9c0..0d11ab4304d 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml test-webapps-parent diff --git a/tests/test-webapps/test-jaas-webapp/pom.xml b/tests/test-webapps/test-jaas-webapp/pom.xml index e3d0047c21e..34ab3005e47 100644 --- a/tests/test-webapps/test-jaas-webapp/pom.xml +++ b/tests/test-webapps/test-jaas-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-jaas-webapp Jetty Tests :: WebApp :: JAAS diff --git a/tests/test-webapps/test-jetty-webapp/pom.xml b/tests/test-webapps/test-jetty-webapp/pom.xml index b952e3c4d3f..e45681105e1 100644 --- a/tests/test-webapps/test-jetty-webapp/pom.xml +++ b/tests/test-webapps/test-jetty-webapp/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests test-webapps-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-webapps/test-jndi-webapp/pom.xml b/tests/test-webapps/test-jndi-webapp/pom.xml index 04b130d2be6..dfcea3f6481 100644 --- a/tests/test-webapps/test-jndi-webapp/pom.xml +++ b/tests/test-webapps/test-jndi-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-jndi-webapp Jetty Tests :: WebApp :: JNDI diff --git a/tests/test-webapps/test-mock-resources/pom.xml b/tests/test-webapps/test-mock-resources/pom.xml index 7704f0ccd3e..3083716570b 100644 --- a/tests/test-webapps/test-mock-resources/pom.xml +++ b/tests/test-webapps/test-mock-resources/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-webapps-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT Jetty Tests :: WebApp :: Mock Resources test-mock-resources diff --git a/tests/test-webapps/test-proxy-webapp/pom.xml b/tests/test-webapps/test-proxy-webapp/pom.xml index 629a792c9e5..a3448f8fbab 100644 --- a/tests/test-webapps/test-proxy-webapp/pom.xml +++ b/tests/test-webapps/test-proxy-webapp/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests test-webapps-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/tests/test-webapps/test-servlet-spec/pom.xml b/tests/test-webapps/test-servlet-spec/pom.xml index e1baa56d470..98c4aeca14f 100644 --- a/tests/test-webapps/test-servlet-spec/pom.xml +++ b/tests/test-webapps/test-servlet-spec/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-webapps-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-servlet-spec-parent Jetty Tests :: Spec Test WebApp :: Parent diff --git a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml index e7939f8cb0f..7f5f90cbaf0 100644 --- a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-container-initializer jar diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml index 0246904e8db..7a9dcc3a2e9 100644 --- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT Jetty Tests :: Webapps :: Spec Webapp test-spec-webapp diff --git a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml index 67c7d86508e..e9469b8b8a8 100644 --- a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.tests test-servlet-spec-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT Jetty Tests :: WebApp :: Servlet Spec :: Fragment Jar org.eclipse.jetty.tests diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml index 40401a12f89..803813f565c 100644 --- a/tests/test-webapps/test-webapp-rfc2616/pom.xml +++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-webapps-parent - 10.0.0-SNAPSHOT + 9.3.0-SNAPSHOT test-webapp-rfc2616 Jetty Tests :: WebApp :: RFC2616 From 272e1d8da590c40cb8caa27f1614e0b7e5c63d65 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 17 Jun 2014 00:02:50 +0200 Subject: [PATCH 089/269] Refactored HttpChannel to not have direct HttpParser dependency --- .../client/http/HttpReceiverOverHTTP.java | 2 +- .../fcgi/parser/ResponseContentParser.java | 4 +- .../fcgi/server/HttpChannelOverFCGI.java | 34 ++-- .../fcgi/server/ServerFCGIConnection.java | 19 +-- .../org/eclipse/jetty/http/BadMessage.java | 12 +- .../org/eclipse/jetty/http/HttpParser.java | 79 ++++----- .../org/eclipse/jetty/http/HttpTester.java | 11 +- .../java/org/eclipse/jetty/http/HttpURI.java | 9 ++ .../org/eclipse/jetty/http}/MetaData.java | 60 ++++--- .../http/HttpGeneratorServerHTTPTest.java | 2 +- .../eclipse/jetty/http/HttpParserTest.java | 134 +++++++-------- .../jetty/http2/frames/HeadersFrame.java | 2 +- .../jetty/http2/frames/PushPromiseFrame.java | 2 +- .../http2/generator/HeadersGenerator.java | 2 +- .../http2/generator/PushPromiseGenerator.java | 2 +- .../jetty/http2/parser/HeaderBlockParser.java | 2 +- .../jetty/http2/parser/HeadersBodyParser.java | 2 +- .../http2/parser/PushPromiseBodyParser.java | 2 +- .../frames/HeadersGenerateParseTest.java | 13 +- .../frames/PushPromiseGenerateParseTest.java | 13 +- .../jetty/http2/hpack/HpackDecoder.java | 1 + .../jetty/http2/hpack/HpackEncoder.java | 5 +- .../jetty/http2/hpack/MetaDataBuilder.java | 8 +- .../jetty/http2/hpack/HpackDecoderTest.java | 25 +-- .../jetty/http2/hpack/HpackEncoderTest.java | 20 +-- .../eclipse/jetty/http2/hpack/HpackTest.java | 12 +- .../http2/server/HttpChannelOverHTTP2.java | 90 ++++------- .../http2/server/HttpInputOverHTTP2.java | 33 +--- .../http2/server/HttpTransportOverHTTP2.java | 4 +- .../jetty/http2/server/HTTP2ServerTest.java | 10 +- .../jetty/security/SecurityHandler.java | 2 +- .../jetty/server/AsyncContextState.java | 2 +- .../server/ByteBufferQueuedHttpInput.java | 53 ------ .../org/eclipse/jetty/server/HttpChannel.java | 149 ++++++++--------- .../jetty/server/HttpChannelOverHttp.java | 152 +++++++++++++----- .../jetty/server/HttpChannelState.java | 6 +- .../eclipse/jetty/server/HttpConnection.java | 10 +- .../org/eclipse/jetty/server/HttpInput.java | 76 +++++++-- .../jetty/server/HttpInputOverHTTP.java | 36 +---- .../org/eclipse/jetty/server/HttpOutput.java | 6 +- .../eclipse/jetty/server/QueuedHttpInput.java | 22 +-- .../org/eclipse/jetty/server/Request.java | 10 +- .../org/eclipse/jetty/server/Response.java | 6 +- .../java/org/eclipse/jetty/server/Server.java | 4 +- .../jetty/server/handler/IPAccessHandler.java | 2 +- .../jetty/server/ExtendedServerTest.java | 2 +- .../jetty/server/HttpConnectionTest.java | 10 +- .../eclipse/jetty/server/HttpWriterTest.java | 10 +- .../jetty/server/QueuedHttpInputTest.java | 2 +- .../org/eclipse/jetty/server/RequestTest.java | 42 ++--- .../eclipse/jetty/server/ResponseTest.java | 6 +- .../jetty/servlets/AsyncGzipFilter.java | 2 +- .../jetty/servlets/gzip/GzipHttpOutput.java | 2 +- .../spdy/server/http/HttpChannelOverSPDY.java | 2 +- .../spdy/server/http/HttpInputOverSPDY.java | 2 +- 55 files changed, 617 insertions(+), 613 deletions(-) rename {jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack => jetty-http/src/main/java/org/eclipse/jetty/http}/MetaData.java (77%) delete mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index 34e586f5ee1..58447d50e5f 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -35,7 +35,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.CompletableCallback; -public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.ResponseHandler +public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.ResponseHandler { private final HttpParser parser = new HttpParser(this); private ByteBuffer buffer; diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java index ef82e32fdfd..61686608f97 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java @@ -71,7 +71,7 @@ public class ResponseContentParser extends StreamContentParser parsers.remove(request); } - private class ResponseParser implements HttpParser.ResponseHandler + private class ResponseParser implements HttpParser.ResponseHandler { private final HttpFields fields = new HttpFields(); private ClientParser.Listener listener; @@ -292,7 +292,7 @@ public class ResponseContentParser extends StreamContentParser // Methods overridden to make them visible here private static class FCGIHttpParser extends HttpParser { - private FCGIHttpParser(ResponseHandler handler) + private FCGIHttpParser(ResponseHandler handler) { super(handler, 65 * 1024, true); reset(); diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java index 39ef42b081c..e7e701d695a 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java @@ -27,10 +27,14 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.fcgi.FCGI; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpChannel; @@ -40,18 +44,19 @@ import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class HttpChannelOverFCGI extends HttpChannel +public class HttpChannelOverFCGI extends HttpChannel { private static final Logger LOG = Log.getLogger(HttpChannelOverFCGI.class); - private final List fields = new ArrayList<>(); + private final HttpFields fields = new HttpFields(); private final Dispatcher dispatcher; private String method; private String path; private String query; private String version; + private HostPortHttpField host; - public HttpChannelOverFCGI(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) + public HttpChannelOverFCGI(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) { super(connector, configuration, endPoint, transport, input); this.dispatcher = new Dispatcher(connector.getExecutor(), this); @@ -67,26 +72,25 @@ public class HttpChannelOverFCGI extends HttpChannel query = field.getValue(); else if (FCGI.Headers.SERVER_PROTOCOL.equalsIgnoreCase(field.getName())) version = field.getValue(); + else if (field.getHeader()==HttpHeader.HOST) + { + host=new HostPortHttpField(HttpHeader.HOST,HttpHeader.HOST.asString(),field.getValue()); + fields.add(host); + } else fields.add(field); } - @Override - public boolean headerComplete() + public void onRequest() { String uri = path; if (query != null && query.length() > 0) uri += "?" + query; - startRequest(method, new HttpURI(uri),HttpVersion.fromString(version)); - - for (HttpField fcgiField : fields) - { - HttpField httpField = convertHeader(fcgiField); - if (httpField != null) - parsedHeader(httpField); - } - - return super.headerComplete(); + + if (host==null) + onRequest(new MetaData.Request(HttpVersion.fromString(version),method,new HttpURI(uri),fields,null,0)); + else + onRequest(new MetaData.Request(HttpVersion.fromString(version),method,new HttpURI(uri),fields,host.getHost(),host.getPort())); } private HttpField convertHeader(HttpField field) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java index 027bf00daa8..c76734eed12 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java @@ -29,9 +29,10 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.ByteBufferQueuedHttpInput; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpInput; +import org.eclipse.jetty.server.QueuedHttpInput; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -122,7 +123,7 @@ public class ServerFCGIConnection extends AbstractConnection // TODO: handle flags HttpChannelOverFCGI channel = new HttpChannelOverFCGI(connector, configuration, getEndPoint(), new HttpTransportOverFCGI(connector.getByteBufferPool(), flusher, request, sendStatus200), - new ByteBufferQueuedHttpInput()); + new QueuedHttpInput()); HttpChannelOverFCGI existing = channels.putIfAbsent(request, channel); if (existing != null) throw new IllegalStateException(); @@ -148,8 +149,8 @@ public class ServerFCGIConnection extends AbstractConnection LOG.debug("Request {} headers on {}", request, channel); if (channel != null) { - if (channel.headerComplete()) - channel.dispatch(); + channel.onRequest(); + channel.dispatch(); } } @@ -161,8 +162,8 @@ public class ServerFCGIConnection extends AbstractConnection LOG.debug("Request {} {} content {} on {}", request, stream, buffer, channel); if (channel != null) { - if (channel.content(buffer)) - channel.dispatch(); + // TODO avoid creating content all the time + channel.onContent(new HttpInput.Content(buffer)); } return false; } @@ -175,8 +176,8 @@ public class ServerFCGIConnection extends AbstractConnection LOG.debug("Request {} end on {}", request, channel); if (channel != null) { - if (channel.messageComplete()) - channel.dispatch(); + channel.onRequestComplete(); + channel.dispatch(); } } @@ -188,7 +189,7 @@ public class ServerFCGIConnection extends AbstractConnection LOG.debug("Request {} failure on {}: {}", request, channel, failure); if (channel != null) { - channel.badMessage(400, failure.toString()); + channel.onBadMessage(400, failure.toString()); } } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java index c21beff3ce1..e92bd5e8ce4 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java @@ -20,33 +20,33 @@ package org.eclipse.jetty.http; /* ------------------------------------------------------------------------------- */ -class BadMessage extends Error +public class BadMessage extends Error { final int _code; final String _reason; - BadMessage() + public BadMessage() { this(400,null); } - BadMessage(int code) + public BadMessage(int code) { this(code,null); } - BadMessage(String reason) + public BadMessage(String reason) { this(400,reason); } - BadMessage(int code,String reason) + public BadMessage(int code,String reason) { _code=code; _reason=reason; } - BadMessage(int code,String reason,Throwable cause) + public BadMessage(int code,String reason,Throwable cause) { super(cause); _code=code; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index e0a7e9552c4..6478c54d08a 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -122,9 +122,9 @@ public class HttpParser } private final boolean DEBUG=LOG.isDebugEnabled(); // Cache debug to help branch prediction - private final HttpHandler _handler; - private final RequestHandler _requestHandler; - private final ResponseHandler _responseHandler; + private final HttpHandler _handler; + private final RequestHandler _requestHandler; + private final ResponseHandler _responseHandler; private final int _maxHeaderBytes; private final boolean _strict; private HttpField _field; @@ -207,31 +207,31 @@ public class HttpParser } /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler) + public HttpParser(RequestHandler handler) { this(handler,-1,__STRICT); } /* ------------------------------------------------------------------------------- */ - public HttpParser(ResponseHandler handler) + public HttpParser(ResponseHandler handler) { this(handler,-1,__STRICT); } /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler,int maxHeaderBytes) + public HttpParser(RequestHandler handler,int maxHeaderBytes) { this(handler,maxHeaderBytes,__STRICT); } /* ------------------------------------------------------------------------------- */ - public HttpParser(ResponseHandler handler,int maxHeaderBytes) + public HttpParser(ResponseHandler handler,int maxHeaderBytes) { this(handler,maxHeaderBytes,__STRICT); } /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler,int maxHeaderBytes,boolean strict) + public HttpParser(RequestHandler handler,int maxHeaderBytes,boolean strict) { _handler=handler; _requestHandler=handler; @@ -241,7 +241,7 @@ public class HttpParser } /* ------------------------------------------------------------------------------- */ - public HttpParser(ResponseHandler handler,int maxHeaderBytes,boolean strict) + public HttpParser(ResponseHandler handler,int maxHeaderBytes,boolean strict) { _handler=handler; _requestHandler=null; @@ -799,20 +799,11 @@ public class HttpParser case HOST: _host=true; - HostPortHttpField hpfield; - if (_field!=null) + if (!(_field instanceof HostPortHttpField)) { - hpfield = (HostPortHttpField)_field; - } - else - { - _field=hpfield=new HostPortHttpField(_header,_strict?_headerString:_header.asString(),_valueString); + _field=new HostPortHttpField(_header,_strict?_headerString:_header.asString(),_valueString); add_to_connection_trie=_connectionFields!=null; } - - if (_requestHandler!=null) - _requestHandler.parsedHostHeader(hpfield.getHost(),hpfield.getPort()); - break; case CONNECTION: @@ -1241,20 +1232,40 @@ public class HttpParser { BufferUtil.clear(buffer); - LOG.warn("badMessage: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler); - if (DEBUG) - LOG.debug(e); + Throwable cause = e.getCause(); + boolean stack = (cause instanceof RuntimeException) || (cause instanceof Error) || LOG.isDebugEnabled(); + if (stack) + LOG.warn("bad HTTP parsed: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler,e); + else + LOG.warn("bad HTTP parsed: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler); setState(State.CLOSED); _handler.badMessage(e.getCode(), e.getReason()); return false; } - catch(Exception e) + catch(NumberFormatException|IllegalStateException e) + { + BufferUtil.clear(buffer); + LOG.warn("parse exception: "+e.toString()+" for "+_handler); + if (DEBUG) + LOG.debug(e); + if (_state.ordinal()<=State.END.ordinal()) + { + setState(State.CLOSED); + _handler.badMessage(400,null); + } + else + { + _handler.earlyEOF(); + setState(State.CLOSED); + } + + return false; + } + catch(Exception|Error e) { BufferUtil.clear(buffer); - LOG.warn("badMessage: "+e.toString()+" for "+_handler); - if (DEBUG) - LOG.debug(e); + LOG.warn("parse exception: "+e.toString()+" for "+_handler,e); if (_state.ordinal()<=State.END.ordinal()) { @@ -1507,9 +1518,9 @@ public class HttpParser * headerComplete then messageComplete) from the same point in the parsing * then it is sufficient for the caller to process the events only once. */ - public interface HttpHandler + public interface HttpHandler { - public boolean content(T item); + public boolean content(ByteBuffer item); public boolean headerComplete(); @@ -1547,7 +1558,7 @@ public class HttpParser - public interface RequestHandler extends HttpHandler + public interface RequestHandler extends HttpHandler { /** * This is the method called by parser when the HTTP request line is parsed @@ -1558,15 +1569,9 @@ public class HttpParser */ public boolean startRequest(String method, HttpURI uri, HttpVersion version); - /** - * This is the method called by the parser after it has parsed the host header (and checked it's format). This is - * called after the {@link HttpHandler#parsedHeader(HttpField)} methods and before - * HttpHandler#headerComplete(); - */ - public void parsedHostHeader(String host,int port); } - public interface ResponseHandler extends HttpHandler + public interface ResponseHandler extends HttpHandler { /** * This is the method called by parser when the HTTP request line is parsed diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java index a7f081e76af..54a99779463 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java @@ -73,7 +73,7 @@ public class HttpTester } - public abstract static class Message extends HttpFields implements HttpParser.HttpHandler + public abstract static class Message extends HttpFields implements HttpParser.HttpHandler { ByteArrayOutputStream _content; HttpVersion _version=HttpVersion.HTTP_1_0; @@ -249,7 +249,7 @@ public class HttpTester } - public static class Request extends Message implements HttpParser.RequestHandler + public static class Request extends Message implements HttpParser.RequestHandler { private String _method; private String _uri; @@ -299,14 +299,9 @@ public class HttpTester { put(name,value); } - - @Override - public void parsedHostHeader(String host,int port) - { - } } - public static class Response extends Message implements HttpParser.ResponseHandler + public static class Response extends Message implements HttpParser.ResponseHandler { private int _status; private String _reason; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index afe925e1ca8..911922f45c8 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -776,6 +776,15 @@ public class HttpURI return _rawString; } + public boolean equals(Object o) + { + if (o==this) + return true; + if (!(o instanceof HttpURI)) + return false; + return toString().equals(o.toString()); + } + public void writeTo(Utf8StringBuilder buf) { buf.append(_raw,_scheme,_end-_scheme); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java similarity index 77% rename from jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java rename to jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index be41545a11a..5a28f74e38f 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -17,26 +17,29 @@ // -package org.eclipse.jetty.http2.hpack; +package org.eclipse.jetty.http; import java.util.Iterator; import java.util.List; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpScheme; - /* ------------------------------------------------------------ */ /** */ public class MetaData implements Iterable { + private final HttpVersion _version; private final HttpFields _fields; - public MetaData(HttpFields fields) + public MetaData(HttpVersion version,HttpFields fields) { _fields=fields; + _version=version; + } + + public HttpVersion getHttpVersion() + { + return _version; } public boolean isRequest() @@ -99,19 +102,34 @@ public class MetaData implements Iterable { private final String _method; private final HttpScheme _scheme; - private final String _authority; private final String _host; private final int _port; - private final String _path; + private final HttpURI _uri; - public Request(HttpScheme scheme, String method, String authority, String host, int port, String path, HttpFields fields) + public Request(HttpVersion version, String method, HttpURI uri, HttpFields fields,String host, int port) { - super(fields); - _authority=authority; + super(version,fields); _host=host; _port=port; _method=method; - _path=path; + _uri=uri; + String scheme=uri.getScheme(); + if (scheme==null) + _scheme=HttpScheme.HTTP; + else + { + HttpScheme s = HttpScheme.CACHE.get(scheme); + _scheme=s==null?HttpScheme.HTTP:s; + } + } + + public Request(HttpVersion version, HttpScheme scheme, String method, String authority, String host, int port, String path, HttpFields fields) + { + super(version,fields); + _host=host; + _port=port; + _method=method; + _uri=new HttpURI(path); // TODO - this is not so efficient! _scheme=scheme; } @@ -137,11 +155,6 @@ public class MetaData implements Iterable return _scheme; } - public String getAuthority() - { - return _authority; - } - public String getHost() { return _host; @@ -152,9 +165,9 @@ public class MetaData implements Iterable return _port; } - public String getPath() + public HttpURI getURI() { - return _path; + return _uri; } @Override @@ -165,8 +178,7 @@ public class MetaData implements Iterable Request r = (Request)o; if (!_method.equals(r._method) || !_scheme.equals(r._scheme) || - !_authority.equals(r._authority) || - !_path.equals(r._path)) + !_uri.equals(r._uri)) return false; return super.equals(o); } @@ -174,7 +186,7 @@ public class MetaData implements Iterable @Override public String toString() { - return _method+" "+_scheme+"://"+_authority+_path+" HTTP/2\n"+super.toString(); + return _method+" "+_scheme+"://"+_host+':'+_port+_uri+" HTTP/2\n"+super.toString(); } } @@ -186,9 +198,9 @@ public class MetaData implements Iterable { private final int _status; - public Response(int status, HttpFields fields) + public Response(HttpVersion version, int status, HttpFields fields) { - super(fields); + super(version,fields); _status=status; } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java index 5fc8436bfb9..02bf214de2a 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java @@ -216,7 +216,7 @@ public class HttpGeneratorServerHTTPTest } } - private class Handler implements HttpParser.ResponseHandler + private class Handler implements HttpParser.ResponseHandler { @Override public boolean content(ByteBuffer ref) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 8b25973d8c8..50ac163f9e8 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -68,7 +68,7 @@ public class HttpParserTest { ByteBuffer buffer= BufferUtil.toBuffer("POST /foo HTTP/1.0\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertEquals("POST", _methodOrVersion); @@ -83,7 +83,7 @@ public class HttpParserTest ByteBuffer buffer= BufferUtil.toBuffer("GET /999\015\012"); _versionOrReason= null; - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -96,7 +96,7 @@ public class HttpParserTest ByteBuffer buffer= BufferUtil.toBuffer("POST /222 \015\012"); _versionOrReason= null; - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertEquals("HTTP/0.9 not supported", _bad); @@ -107,7 +107,7 @@ public class HttpParserTest { ByteBuffer buffer= BufferUtil.toBuffer("POST /fo\u0690 HTTP/1.0\015\012" + "\015\012",StandardCharsets.UTF_8); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertEquals("POST", _methodOrVersion); @@ -121,7 +121,7 @@ public class HttpParserTest { ByteBuffer buffer= BufferUtil.toBuffer("POST /foo?param=\u0690 HTTP/1.0\015\012" + "\015\012",StandardCharsets.UTF_8); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertEquals("POST", _methodOrVersion); @@ -135,7 +135,7 @@ public class HttpParserTest { ByteBuffer buffer= BufferUtil.toBuffer("POST /123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/ HTTP/1.0\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertEquals("POST", _methodOrVersion); @@ -148,7 +148,7 @@ public class HttpParserTest public void testConnect() throws Exception { ByteBuffer buffer= BufferUtil.toBuffer("CONNECT 192.168.1.2:80 HTTP/1.1\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertEquals("CONNECT", _methodOrVersion); @@ -166,7 +166,7 @@ public class HttpParserTest "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -192,7 +192,7 @@ public class HttpParserTest " extra\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -210,7 +210,7 @@ public class HttpParserTest " Name: value\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -270,7 +270,7 @@ public class HttpParserTest BufferUtil.put(b0,buffer); BufferUtil.flipToFlush(buffer,pos); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -316,7 +316,7 @@ public class HttpParserTest "Accept-Encoding: gzip, deflated\015\012" + "Accept: unknown\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -364,7 +364,7 @@ public class HttpParserTest "Accept-Encoding: gzip, deflated\n" + "Accept: unknown\n" + "\n"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -403,7 +403,7 @@ public class HttpParserTest "Name1: \"value\t1\"\n" + "Name2: \"value\t2A\",\"value,2B\"\t\n" + "\n"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -432,7 +432,7 @@ public class HttpParserTest BufferUtil.put(BufferUtil.toBuffer(" \r\n\r\n"),buffer); BufferUtil.flipToFlush(buffer,0); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -453,7 +453,7 @@ public class HttpParserTest ByteBuffer buffer= BufferUtil.toBuffer( "G\u00e6T / HTTP/1.0\r\nHeader0: value0\r\n\n\n"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertThat(_bad,Matchers.notNullValue()); @@ -465,7 +465,7 @@ public class HttpParserTest ByteBuffer buffer= BufferUtil.toBuffer( "GET / H\u00e6P/1.0\r\nHeader0: value0\r\n\n\n"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertThat(_bad,Matchers.notNullValue()); @@ -478,7 +478,7 @@ public class HttpParserTest ByteBuffer buffer= BufferUtil.toBuffer( "GET / HTTP/1.0\r\nH\u00e6der0: value0\r\n\n\n"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertThat(_bad,Matchers.notNullValue()); @@ -493,7 +493,7 @@ public class HttpParserTest "Header: value\talternate\r\n" + "\n\n"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -514,7 +514,7 @@ public class HttpParserTest "HOST: localhost\015\012" + "cOnNeCtIoN: ClOsE\015\012"+ "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler,-1,false); parseAll(parser,buffer); @@ -536,7 +536,7 @@ public class HttpParserTest "HOST: localhost\015\012" + "cOnNeCtIoN: ClOsE\015\012"+ "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler,-1,true); parseAll(parser,buffer); @@ -568,7 +568,7 @@ public class HttpParserTest for (int i=0;i handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); // System.err.println(BufferUtil.toDetailString(buffer)); @@ -618,7 +618,7 @@ public class HttpParserTest + "1a\015\012" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ\015\012" + "0\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); @@ -634,7 +634,7 @@ public class HttpParserTest @Test public void testStartEOF() throws Exception { - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.atEOF(); parser.parseNext(BufferUtil.EMPTY_BUFFER); @@ -651,7 +651,7 @@ public class HttpParserTest + "Content-Length: 20\015\012" + "\015\012" + "0123456789"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.atEOF(); parseAll(parser,buffer); @@ -674,7 +674,7 @@ public class HttpParserTest + "\015\012" + "a;\015\012" + "0123456789\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.atEOF(); parseAll(parser,buffer); @@ -722,7 +722,7 @@ public class HttpParserTest + "\015\012" + "0123456789\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("GET", _methodOrVersion); @@ -790,7 +790,7 @@ public class HttpParserTest + "0123456789\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer0); parser.atEOF(); @@ -836,7 +836,7 @@ public class HttpParserTest + "\015\012" + "0123456789\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("HTTP/1.1", _methodOrVersion); @@ -855,7 +855,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("HTTP/1.1", _methodOrVersion); @@ -879,7 +879,7 @@ public class HttpParserTest + "\015\012" + "0123456789\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("HTTP/1.1", _methodOrVersion); @@ -912,7 +912,7 @@ public class HttpParserTest + "\015\012" + "0123456789\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("HTTP/1.1", _methodOrVersion); @@ -933,7 +933,7 @@ public class HttpParserTest + "\015\012" + "0123456789\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("HTTP/1.1", _methodOrVersion); @@ -953,7 +953,7 @@ public class HttpParserTest + "\015\012" + "0123456789\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.atEOF(); parser.parseNext(buffer); @@ -975,7 +975,7 @@ public class HttpParserTest + "Content-Length: 10\015\012" + "\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("HTTP/1.1", _methodOrVersion); @@ -994,7 +994,7 @@ public class HttpParserTest + "Transfer-Encoding: chunked\015\012" + "\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("HTTP/1.1", _methodOrVersion); @@ -1017,7 +1017,7 @@ public class HttpParserTest + "HTTP/1.1 400 OK\015\012"); // extra data causes close ?? - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1045,7 +1045,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1065,7 +1065,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1084,7 +1084,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1103,7 +1103,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1122,7 +1122,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.ResponseHandler handler = new Handler(); + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1141,7 +1141,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1175,7 +1175,7 @@ public class HttpParserTest + "Connection: close\r" + "\r"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1211,7 +1211,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1230,7 +1230,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1249,7 +1249,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); @@ -1268,7 +1268,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("host",_host); @@ -1283,7 +1283,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("No Host",_bad); @@ -1298,7 +1298,7 @@ public class HttpParserTest "GET http://host/ HTTP/1.0\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); Assert.assertNull(_bad); @@ -1314,7 +1314,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("No Host",_bad); @@ -1329,7 +1329,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("192.168.0.1",_host); @@ -1345,7 +1345,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("::1",_host); @@ -1361,7 +1361,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); Assert.assertThat(_bad,Matchers.containsString("Bad")); @@ -1376,7 +1376,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("myhost",_host); @@ -1392,7 +1392,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); Assert.assertThat(_bad,Matchers.containsString("Bad Host")); @@ -1407,7 +1407,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("192.168.0.1",_host); @@ -1423,7 +1423,7 @@ public class HttpParserTest + "Connection: close\015\012" + "\015\012"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); assertEquals("::1",_host); @@ -1438,7 +1438,7 @@ public class HttpParserTest "Host: www.smh.com.au\r\n"+ "\r\n"); - HttpParser.RequestHandler handler = new Handler(); + HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parseAll(parser,buffer); assertEquals("www.smh.com.au",parser.getFieldCache().get("Host: www.smh.com.au").getValue()); @@ -1540,7 +1540,7 @@ public class HttpParserTest private boolean _headerCompleted; private boolean _messageCompleted; - private class Handler implements HttpParser.RequestHandler, HttpParser.ResponseHandler, HttpParser.ProxyHandler + private class Handler implements HttpParser.RequestHandler, HttpParser.ResponseHandler, HttpParser.ProxyHandler { private HttpFields fields; String _proxy; @@ -1582,13 +1582,13 @@ public class HttpParserTest //System.err.println("header "+name+": "+value); _hdr[++_headers]= field.getName(); _val[_headers]= field.getValue(); - } - - @Override - public void parsedHostHeader(String host,int port) - { - _host=host; - _port=port; + + if (field instanceof HostPortHttpField) + { + HostPortHttpField hpfield = (HostPortHttpField)field; + _host=hpfield.getHost(); + _port=hpfield.getPort(); + } } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java index dfb81246a4f..649006d2f7b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java @@ -18,7 +18,7 @@ package org.eclipse.jetty.http2.frames; -import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http.MetaData; public class HeadersFrame extends Frame { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java index 47dc39cbdfc..a1c44124957 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java @@ -18,7 +18,7 @@ package org.eclipse.jetty.http2.frames; -import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http.MetaData; public class PushPromiseFrame extends Frame { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index 1229fdc17ef..6aea9cdb6f2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -20,12 +20,12 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index 38ef5b38de2..4c7bcb60bb9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -25,7 +25,7 @@ import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java index 1a8fb509fc5..ff724676bc0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java @@ -20,8 +20,8 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackDecoder; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 7c66e91caa0..17e33b43d75 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -20,10 +20,10 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.util.BufferUtil; public class HeadersBodyParser extends BodyParser diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java index 87074ae6282..fd1a101515d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -21,7 +21,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.frames.PushPromiseFrame; -import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http.MetaData; public class PushPromiseBodyParser extends BodyParser { diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 6e2cefcba7a..38aa07281a7 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -25,10 +25,11 @@ import java.util.List; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.HeadersGenerator; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -50,7 +51,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); @@ -84,10 +85,9 @@ public class HeadersGenerateParseTest MetaData.Request request = (MetaData.Request)frame.getMetaData(); Assert.assertSame(metaData.getScheme(), request.getScheme()); Assert.assertEquals(metaData.getMethod(), request.getMethod()); - Assert.assertEquals(metaData.getAuthority(), request.getAuthority()); Assert.assertEquals(metaData.getHost(), request.getHost()); Assert.assertEquals(metaData.getPort(), request.getPort()); - Assert.assertEquals(metaData.getPath(), request.getPath()); + Assert.assertEquals(metaData.getURI(), request.getURI()); for (int j = 0; j < fields.size(); ++j) { HttpField field = fields.getField(j); @@ -105,7 +105,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -135,10 +135,9 @@ public class HeadersGenerateParseTest MetaData.Request request = (MetaData.Request)frame.getMetaData(); Assert.assertSame(metaData.getScheme(), request.getScheme()); Assert.assertEquals(metaData.getMethod(), request.getMethod()); - Assert.assertEquals(metaData.getAuthority(), request.getAuthority()); Assert.assertEquals(metaData.getHost(), request.getHost()); Assert.assertEquals(metaData.getPort(), request.getPort()); - Assert.assertEquals(metaData.getPath(), request.getPath()); + Assert.assertEquals(metaData.getURI(), request.getURI()); for (int j = 0; j < fields.size(); ++j) { HttpField field = fields.getField(j); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index ebbf88fc56b..7ebc775545c 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -25,10 +25,11 @@ import java.util.List; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.PushPromiseGenerator; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http2.hpack.MetaData; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -51,7 +52,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); @@ -85,10 +86,9 @@ public class PushPromiseGenerateParseTest MetaData.Request request = (MetaData.Request)frame.getMetaData(); Assert.assertSame(metaData.getScheme(), request.getScheme()); Assert.assertEquals(metaData.getMethod(), request.getMethod()); - Assert.assertEquals(metaData.getAuthority(), request.getAuthority()); Assert.assertEquals(metaData.getHost(), request.getHost()); Assert.assertEquals(metaData.getPort(), request.getPort()); - Assert.assertEquals(metaData.getPath(), request.getPath()); + Assert.assertEquals(metaData.getURI(), request.getURI()); for (int j = 0; j < fields.size(); ++j) { HttpField field = fields.getField(j); @@ -107,7 +107,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -137,10 +137,9 @@ public class PushPromiseGenerateParseTest MetaData.Request request = (MetaData.Request)frame.getMetaData(); Assert.assertSame(metaData.getScheme(), request.getScheme()); Assert.assertEquals(metaData.getMethod(), request.getMethod()); - Assert.assertEquals(metaData.getAuthority(), request.getAuthority()); Assert.assertEquals(metaData.getHost(), request.getHost()); Assert.assertEquals(metaData.getPort(), request.getPort()); - Assert.assertEquals(metaData.getPath(), request.getPath()); + Assert.assertEquals(metaData.getURI(), request.getURI()); for (int j = 0; j < fields.size(); ++j) { HttpField field = fields.getField(j); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index a31df90c158..fa7fbe08eb2 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 5345050f6ad..97bc303a601 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -25,6 +25,7 @@ import java.util.EnumSet; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.io.ByteBufferPool.Lease; import org.eclipse.jetty.util.BufferUtil; @@ -136,8 +137,8 @@ public class HpackEncoder // TODO optimise these to avoid HttpField creation encode(buffer,new HttpField(":scheme",request.getScheme().asString())); encode(buffer,new HttpField(":method",request.getMethod())); - encode(buffer,new HttpField(":authority",request.getAuthority())); // TODO look for host header? - encode(buffer,new HttpField(":path",request.getPath())); + encode(buffer,new HttpField(":authority",request.getPort()>0?(request.getHost()+':'+request.getPort()):request.getHost())); + encode(buffer,new HttpField(":path",request.getURI().getPath())); } else if (metadata.isResponse()) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 8c1697d63c9..94f4c55c036 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -24,6 +24,8 @@ import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ @@ -105,10 +107,10 @@ public class MetaDataBuilder HttpFields fields = _fields; _fields = new HttpFields(Math.max(10,fields.size()+5)); if (_method!=null) - return new MetaData.Request(_scheme,_method,_authority,_host,_port,_path,fields); + return new MetaData.Request(HttpVersion.HTTP_2_0,_scheme,_method,_authority,_host,_port,_path,fields); if (_status!=0) - return new MetaData.Response(_status,fields); - return new MetaData(fields); + return new MetaData.Response(HttpVersion.HTTP_2_0,_status,fields); + return new MetaData(HttpVersion.HTTP_2_0,fields); } finally { diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index 23a97ccd22b..7857a1bdbfd 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -25,6 +25,7 @@ import java.util.Iterator; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.util.TypeUtil; import org.junit.Test; @@ -52,8 +53,8 @@ public class HpackDecoderTest assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getPath()); - assertEquals("www.example.com",request.getAuthority()); + assertEquals("/",request.getURI().getPath()); + assertEquals("www.example.com",request.getHost()); assertFalse(request.iterator().hasNext()); @@ -65,8 +66,8 @@ public class HpackDecoderTest assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getPath()); - assertEquals("www.example.com",request.getAuthority()); + assertEquals("/",request.getURI().getPath()); + assertEquals("www.example.com",request.getHost()); Iterator iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); @@ -81,8 +82,8 @@ public class HpackDecoderTest assertEquals("GET",request.getMethod()); assertEquals(HttpScheme.HTTPS,request.getScheme()); - assertEquals("/index.html",request.getPath()); - assertEquals("www.example.com",request.getAuthority()); + assertEquals("/index.html",request.getURI().getPath()); + assertEquals("www.example.com",request.getHost()); iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); @@ -102,8 +103,8 @@ public class HpackDecoderTest assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getPath()); - assertEquals("www.example.com",request.getAuthority()); + assertEquals("/",request.getURI().getPath()); + assertEquals("www.example.com",request.getHost()); assertFalse(request.iterator().hasNext()); @@ -115,8 +116,8 @@ public class HpackDecoderTest assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getPath()); - assertEquals("www.example.com",request.getAuthority()); + assertEquals("/",request.getURI().getPath()); + assertEquals("www.example.com",request.getHost()); Iterator iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); @@ -130,8 +131,8 @@ public class HpackDecoderTest assertEquals("GET",request.getMethod()); assertEquals(HttpScheme.HTTPS,request.getScheme()); - assertEquals("/index.html",request.getPath()); - assertEquals("www.example.com",request.getAuthority()); + assertEquals("/index.html",request.getURI().getPath()); + assertEquals("www.example.com",request.getHost()); iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index 7dee4b407d3..fa5669c88fd 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -25,6 +25,8 @@ import java.util.HashSet; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; @@ -68,7 +70,7 @@ public class HpackEncoderTest // encode them ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,pos); // something was encoded! @@ -87,7 +89,7 @@ public class HpackEncoderTest // encode exact same fields again! BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,0); // nothing should be encoded! @@ -110,7 +112,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -134,7 +136,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -161,7 +163,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -189,7 +191,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -223,7 +225,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -244,7 +246,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -256,7 +258,7 @@ public class HpackEncoderTest // encode again BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index b6c039848c9..63a1dff5306 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -23,10 +23,11 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpVersion; import org.junit.Assert; import org.junit.Test; -import org.eclipse.jetty.http2.hpack.MetaData.Response; -import org.eclipse.jetty.http2.hpack.MetaData.Request; +import org.eclipse.jetty.http.MetaData.Request; +import org.eclipse.jetty.http.MetaData.Response; import org.eclipse.jetty.util.BufferUtil; @@ -45,7 +46,7 @@ public class HpackTest fields0.add(HttpHeader.SERVER,"jetty"); fields0.add(HttpHeader.SET_COOKIE,"abcdefghijklmnopqrstuvwxyz"); fields0.add("custom-key","custom-value"); - Response original0 = new Response(200,fields0); + Response original0 = new Response(HttpVersion.HTTP_2_0,200,fields0); BufferUtil.clearToFill(buffer); encoder.encode(buffer,original0); @@ -60,15 +61,14 @@ public class HpackTest BufferUtil.flipToFlush(buffer,0); Response decoded0b = (Response)decoder.decode(buffer); - Assert.assertEquals(original0,decoded0b); - + Assert.assertEquals(original0,decoded0b); HttpFields fields1 = new HttpFields(); fields1.add(HttpHeader.CONTENT_TYPE,"text/plain"); fields1.add(HttpHeader.CONTENT_LENGTH,"1234"); fields1.add(HttpHeader.SERVER,"jetty"); fields1.add("custom-key","other-value"); - Response original1 = new Response(200,fields1); + Response original1 = new Response(HttpVersion.HTTP_2_0,200,fields1); // Same again? BufferUtil.clearToFill(buffer); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 9b912c19a44..65993f85c96 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -23,13 +23,10 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; @@ -42,12 +39,13 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class HttpChannelOverHTTP2 extends HttpChannel +public class HttpChannelOverHTTP2 extends HttpChannel { private static final Logger LOG = Log.getLogger(HttpChannelOverHTTP2.class); + private static final HttpField ACCEPT_ENCODING_GZIP = new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip"); private final Stream stream; - public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input, Stream stream) + public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input, Stream stream) { super(connector, configuration, endPoint, transport, input); this.stream = stream; @@ -58,88 +56,66 @@ public class HttpChannelOverHTTP2 extends HttpChannel MetaData metaData = frame.getMetaData(); if (!metaData.isRequest()) { - badMessage(400, null); + onBadMessage(400, null); return; } - MetaData.Request requestMetaData = (MetaData.Request)metaData; - - String method = requestMetaData.getMethod(); - HttpURI uri = new HttpURI(requestMetaData.getPath()); - HttpVersion version = HttpVersion.HTTP_2_0; - - startRequest(method, uri, version); - - HttpScheme scheme = requestMetaData.getScheme(); - if (scheme != null) - { - getRequest().setScheme(scheme.asString()); - } - - parsedHostHeader(requestMetaData.getHost(), requestMetaData.getPort()); + MetaData.Request request = (MetaData.Request)metaData; // The specification says user agents MUST support gzip encoding. // Based on that, some browser does not send the header, but it's // important that applications can find it (e.g. GzipFilter). - boolean hasAcceptEncodingGzip = false; - HttpFields fields = requestMetaData.getFields(); - for (int i = 0; i < fields.size(); ++i) - { - HttpField field = fields.getField(i); - if (HttpHeader.ACCEPT_ENCODING.is(field.getName())) - hasAcceptEncodingGzip = field.getValue().contains("gzip"); - parsedHeader(field); - } - if (!hasAcceptEncodingGzip) - parsedHeader(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip")); - - headerComplete(); + HttpFields fields = request.getFields(); + if (!fields.contains(ACCEPT_ENCODING_GZIP)) + fields.add(ACCEPT_ENCODING_GZIP); + onRequest(request); + if (frame.isEndStream()) { - messageComplete(); + onRequestComplete(); } if (LOG.isDebugEnabled()) { - StringBuilder headers = new StringBuilder(); - for (HttpField field : fields) - { - headers.append(field).append(System.lineSeparator()); - } LOG.debug("HTTP2 Request #{}:{}{} {} {}{}{}", - stream.getId(), System.lineSeparator(), method, uri, version, System.lineSeparator(), headers); + stream.getId(), System.lineSeparator(), request.getMethod(), request.getURI(), request.getHttpVersion(), System.lineSeparator(), fields); } - // TODO: pending refactoring of HttpChannel API. - // Here we "cheat", knowing that headerComplete() will always return true - // and that content() and messageComplete() will always return false. - // This is the only place where we process the channel. execute(this); } - public void requestContent(DataFrame frame, Callback callback) + public void requestContent(DataFrame frame, final Callback callback) { // We must copy the data since we do not know when its bytes will be consumed. - ByteBufferPool byteBufferPool = getByteBufferPool(); + final ByteBufferPool byteBufferPool = getByteBufferPool(); ByteBuffer original = frame.getData(); final ByteBuffer copy = byteBufferPool.acquire(original.remaining(), original.isDirect()); BufferUtil.clearToFill(copy); copy.put(original).flip(); - // TODO: pending refactoring of HttpChannel API (see above). - content(new ByteBufferCallback(byteBufferPool, copy, callback)); + onContent(new HttpInput.Content(copy) + { + @Override + public void succeeded() + { + byteBufferPool.release(copy); + callback.succeeded(); + } + + @Override + public void failed(Throwable x) + { + byteBufferPool.release(copy); + callback.failed(x); + } + + }); if (frame.isEndStream()) { - messageComplete(); + onRequestComplete(); } } - @Override - public boolean messageComplete() - { - super.messageComplete(); - return false; - } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java index 162c006f562..c4445f919bf 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpInputOverHTTP2.java @@ -18,39 +18,8 @@ package org.eclipse.jetty.http2.server; -import java.nio.ByteBuffer; - import org.eclipse.jetty.server.QueuedHttpInput; -public class HttpInputOverHTTP2 extends QueuedHttpInput +public class HttpInputOverHTTP2 extends QueuedHttpInput { - @Override - protected int remaining(ByteBufferCallback item) - { - return item.getByteBuffer().remaining(); - } - - @Override - protected int get(ByteBufferCallback item, byte[] buffer, int offset, int length) - { - ByteBuffer byteBuffer = item.getByteBuffer(); - length = Math.min(byteBuffer.remaining(), length); - byteBuffer.get(buffer, offset, length); - return length; - } - - @Override - protected void consume(ByteBufferCallback item, int length) - { - ByteBuffer byteBuffer = item.getByteBuffer(); - byteBuffer.position(byteBuffer.position() + length); - if (!byteBuffer.hasRemaining()) - onContentConsumed(item); - } - - @Override - protected void onContentConsumed(ByteBufferCallback item) - { - item.succeeded(); - } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 809b5f74034..8f3fcd6dd59 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -24,10 +24,10 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; @@ -85,7 +85,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport stream.getId(), System.lineSeparator(), HttpVersion.HTTP_2_0, info.getStatus(), System.lineSeparator(), info.getHttpFields()); } - MetaData metaData = new MetaData.Response(info.getStatus(), info.getHttpFields()); + MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2_0, info.getStatus(), info.getHttpFields()); HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, endStream); stream.headers(frame, callback); } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 9fadfa8ca4f..2869c3b9350 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -29,6 +29,7 @@ import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -37,6 +38,8 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -46,7 +49,6 @@ import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.hpack.HpackContext; import org.eclipse.jetty.http2.hpack.HpackDecoder; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.PrefaceParser; @@ -103,7 +105,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -152,7 +154,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -215,7 +217,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0,HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index a6e108e9a70..606cf3d9b99 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -323,7 +323,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti public void sessionCreated(HttpSessionEvent se) { //if current request is authenticated, then as we have just created the session, mark it as secure, as it has not yet been returned to a user - HttpChannel channel = HttpChannel.getCurrentHttpChannel(); + HttpChannel channel = HttpChannel.getCurrentHttpChannel(); if (channel == null) return; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java index 6503424dd10..259f32e8e1b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java @@ -147,7 +147,7 @@ public class AsyncContextState implements AsyncContext @Override public boolean hasOriginalRequestAndResponse() { - HttpChannel channel=state().getHttpChannel(); + HttpChannel channel=state().getHttpChannel(); return channel.getRequest()==getRequest() && channel.getResponse()==getResponse(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java deleted file mode 100644 index cd2d12e823a..00000000000 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java +++ /dev/null @@ -1,53 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.server; - -import java.nio.ByteBuffer; - -/** - *

An implementation of HttpInput using {@link ByteBuffer} as items.

- */ -public class ByteBufferQueuedHttpInput extends QueuedHttpInput -{ - @Override - protected int remaining(ByteBuffer item) - { - return item.remaining(); - } - - @Override - protected int get(ByteBuffer item, byte[] buffer, int offset, int length) - { - int l = Math.min(item.remaining(), length); - item.get(buffer, offset, l); - return l; - } - - @Override - protected void consume(ByteBuffer item, int length) - { - item.position(item.position()+length); - } - - @Override - protected void onContentConsumed(ByteBuffer item) - { - } - -} diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index e1e55e30c78..c39721a9e1e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -30,6 +30,7 @@ import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; +import org.eclipse.jetty.http.BadMessage; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; @@ -40,6 +41,7 @@ import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ChannelEndPoint; @@ -67,24 +69,24 @@ import org.eclipse.jetty.util.thread.Scheduler; * HttpTransport.completed(). * */ -public class HttpChannel implements HttpParser.RequestHandler, Runnable +public class HttpChannel implements Runnable { private static final Logger LOG = Log.getLogger(HttpChannel.class); - private static final ThreadLocal> __currentChannel = new ThreadLocal<>(); + private static final ThreadLocal __currentChannel = new ThreadLocal<>(); /* ------------------------------------------------------------ */ /** Get the current channel that this thread is dispatched to. * @see Request#getAttribute(String) for a more general way to access the HttpChannel * @return the current HttpChannel or null */ - public static HttpChannel getCurrentHttpChannel() + public static HttpChannel getCurrentHttpChannel() { return __currentChannel.get(); } - protected static HttpChannel setCurrentHttpChannel(HttpChannel channel) + protected static HttpChannel setCurrentHttpChannel(HttpChannel channel) { - HttpChannel last=__currentChannel.get(); + HttpChannel last=__currentChannel.get(); if (channel==null) __currentChannel.remove(); else @@ -103,7 +105,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable private final Response _response; private HttpVersion _version = HttpVersion.HTTP_1_1; - public HttpChannel(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) + public HttpChannel(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) { _connector = connector; _configuration = configuration; @@ -183,12 +185,6 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable return _endPoint.getRemoteAddress(); } - @Override - public int getHeaderCacheSize() - { - return _configuration.getHeaderCacheSize(); - } - /** * If the associated response has the Expect header set to 100 Continue, * then accessing the input stream indicates that the handler/servlet @@ -222,7 +218,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable { LOG.debug("{} handle enter", this); - final HttpChannellast = setCurrentHttpChannel(this); + final HttpChannel last = setCurrentHttpChannel(this); String threadName = null; if (LOG.isDebugEnabled()) @@ -455,13 +451,35 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable ); } - @Override - public boolean startRequest(String method, HttpURI uri, HttpVersion version) + public void onRequest(MetaData.Request request) { + _requests.incrementAndGet(); + // TODO directly inject MetaData.Request to Request + _request.setTimeStamp(System.currentTimeMillis()); - _request.setMethod(method); - _request.setUri(uri); + _request.setHttpVersion(_version = request.getHttpVersion()); + _request.setMethod(request.getMethod()); + _request.setScheme(request.getScheme().asString()); + + HttpURI uri = request.getURI(); + + String uriHost=uri.getHost(); + if (uriHost!=null) + { + // Give precidence to authority in absolute URI + _request.setServerName(uriHost); + _request.setServerPort(uri.getPort()); + } + else + { + _request.setServerName(request.getHost()); + _request.setServerPort(request.getPort()); + } + + _request.setUri(request.getURI()); + + String path; try @@ -475,7 +493,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable path = uri.getDecodedPath(StandardCharsets.ISO_8859_1); } - String info = URIUtil.canonicalPath(path); + String info = URIUtil.canonicalPath(path); // TODO should this be done prior to decoding??? if (info == null) { @@ -485,93 +503,62 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable _request.setRequestURI(""); } else - { - badMessage(400,null); - return true; - } + throw new BadMessage(400,"Bad URI"); } - _request.setPathInfo(info); - _version = version; - _request.setHttpVersion(_version); - - return false; - } - - @Override - public void parsedHeader(HttpField field) - { - HttpHeader header=field.getHeader(); - String value=field.getValue(); - if (value == null) - value = ""; - if (header != null) + + + // TODO avoid playing in headers + for (HttpField field : request.getFields()) { - switch (header) + HttpHeader header=field.getHeader(); + String value=field.getValue(); + if (value == null) + value = ""; + if (header != null) { - case CONTENT_TYPE: - MimeTypes.Type mime = MimeTypes.CACHE.get(value); - String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString(); - if (charset != null) - _request.setCharacterEncodingUnchecked(charset); - break; - default: + switch (header) + { + case CONTENT_TYPE: + MimeTypes.Type mime = MimeTypes.CACHE.get(value); + String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString(); + if (charset != null) + _request.setCharacterEncodingUnchecked(charset); + break; + default: + } } + + if (field.getName()!=null) + _request.getHttpFields().add(field); } - if (field.getName()!=null) - _request.getHttpFields().add(field); - } - - @Override - public void parsedHostHeader(String host, int port) - { - if (_request.getUri().getHost()==null) - { - _request.setServerName(host); - _request.setServerPort(port); - } - } - - @Override - public boolean headerComplete() - { - _requests.incrementAndGet(); // TODO make this a better field for h2 hpack generation if (_configuration.getSendDateHeader()) _response.getHttpFields().put(_connector.getServer().getDateField()); - - return true; } - @Override - public boolean content(T item) + public void onContent(HttpInput.Content content) { if (LOG.isDebugEnabled()) - LOG.debug("{} content {}", this, item); - @SuppressWarnings("unchecked") - HttpInput input = (HttpInput)_request.getHttpInput(); - input.content(item); - - return false; + LOG.debug("{} content {}", this, content); + + HttpInput input = (HttpInput)_request.getHttpInput(); + input.content(content); } - @Override - public boolean messageComplete() + public void onRequestComplete() { - LOG.debug("{} messageComplete", this); + LOG.debug("{} onRequestComplete", this); _request.getHttpInput().messageComplete(); - return true; } - @Override - public void earlyEOF() + public void onEarlyEOF() { _request.getHttpInput().earlyEOF(); } - @Override - public void badMessage(int status, String reason) + public void onBadMessage(int status, String reason) { if (status < 400 || status > 599) status = HttpStatus.BAD_REQUEST_400; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index a041f52582c..03737eed146 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -23,7 +23,9 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; @@ -32,22 +34,29 @@ import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; /** * A HttpChannel customized to be transported over the HTTP/1 protocol */ -class HttpChannelOverHttp extends HttpChannel implements HttpParser.ProxyHandler +class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandler, HttpParser.ProxyHandler { /** * */ private final HttpConnection _httpConnection; + private String _method; + private HttpURI _uri; + private HttpVersion _version; + private final HttpFields _fields = new HttpFields(); + private HostPortHttpField _hostPort; + private HttpField _connection; private boolean _expect = false; private boolean _expect100Continue = false; private boolean _expect102Processing = false; - public HttpChannelOverHttp(HttpConnection httpConnection, Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) + public HttpChannelOverHttp(HttpConnection httpConnection, Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) { super(connector,config,endPoint,transport,input); _httpConnection = httpConnection; @@ -60,6 +69,12 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. _expect = false; _expect100Continue = false; _expect102Processing = false; + _method=null; + _uri=null; + _version=null; + _hostPort=null; + _connection=null; + _fields.clear(); } @Override @@ -77,15 +92,19 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. @Override public boolean startRequest(String method, HttpURI uri, HttpVersion version) { + _method=method; + _uri=uri; + _version=version; _expect = false; _expect100Continue = false; _expect102Processing = false; - return super.startRequest(method,uri,version); + return false; } @Override public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort) { + _method=HttpMethod.CONNECT.asString(); Request request = getRequest(); request.setAttribute("PROXY", protocol); request.setServerName(sAddr); @@ -99,44 +118,64 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. { HttpHeader header=field.getHeader(); String value=field.getValue(); - if (getRequest().getHttpVersion().getVersion()==HttpVersion.HTTP_1_1.getVersion() && header == HttpHeader.EXPECT) + if (header!=null) { - HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); - switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) + switch(header) { - case CONTINUE: - _expect100Continue = true; + case CONNECTION: + _connection=field; break; - case PROCESSING: - _expect102Processing = true; + case HOST: + _hostPort=(HostPortHttpField)field; break; - default: - String[] values = field.getValues(); - for (int i = 0; values != null && i < values.length; i++) + case EXPECT: + { + if (getRequest().getHttpVersion().getVersion()==HttpVersion.HTTP_1_1.getVersion()) { - expect = HttpHeaderValue.CACHE.get(values[i].trim()); - if (expect == null) - _expect = true; - else + HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); + switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) { - switch (expect) - { - case CONTINUE: - _expect100Continue = true; - break; - case PROCESSING: - _expect102Processing = true; - break; - default: - _expect = true; - } + case CONTINUE: + _expect100Continue = true; + break; + + case PROCESSING: + _expect102Processing = true; + break; + + default: + String[] values = field.getValues(); + for (int i = 0; values != null && i < values.length; i++) + { + expect = HttpHeaderValue.CACHE.get(values[i].trim()); + if (expect == null) + _expect = true; + else + { + switch (expect) + { + case CONTINUE: + _expect100Continue = true; + break; + case PROCESSING: + _expect102Processing = true; + break; + default: + _expect = true; + } + } + } } } + break; + } + default: + break; } } - super.parsedHeader(field); + _fields.add(field); } /** @@ -177,13 +216,14 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. if (getRequest().getMethod()==null) _httpConnection.close(); else - super.earlyEOF(); + onEarlyEOF(); } @Override - public boolean content(ByteBuffer item) + public boolean content(ByteBuffer content) { - super.content(item); + // TODO avoid creating the Content object with wrapper? + onContent(new HttpInput.Content(content)); return true; } @@ -191,24 +231,33 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. public void badMessage(int status, String reason) { _httpConnection._generator.setPersistent(false); - super.badMessage(status,reason); + onBadMessage(status,reason); } @Override public boolean headerComplete() { boolean persistent; - HttpVersion version = getHttpVersion(); - switch (version) + switch (_version) { case HTTP_1_0: { - persistent = getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); + if (_connection!=null) + { + if (_connection.contains(HttpHeaderValue.KEEP_ALIVE.asString())) + persistent=true; + else + persistent=_fields.contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); + } + else + persistent=false; + if (!persistent) persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); if (persistent) getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); + break; } @@ -219,8 +268,17 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. badMessage(HttpStatus.EXPECTATION_FAILED_417,null); return true; } - - persistent = !getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); + + if (_connection!=null) + { + if (_connection.contains(HttpHeaderValue.CLOSE.asString())) + persistent=false; + else + persistent=!_fields.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); // handle multiple connection fields + } + else + persistent=true; + if (!persistent) persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); if (!persistent) @@ -237,7 +295,11 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. if (!persistent) _httpConnection._generator.setPersistent(false); - return super.headerComplete(); + if (_hostPort==null) + onRequest(new MetaData.Request(_version,_method,_uri,_fields,null,0)); + else + onRequest(new MetaData.Request(_version,_method,_uri,_fields,_hostPort.getHost(),_hostPort.getPort())); + return true; } @Override @@ -257,7 +319,17 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser. @Override public boolean messageComplete() { - super.messageComplete(); + onRequestComplete(); return false; } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.HttpParser.HttpHandler#getHeaderCacheSize() + */ + @Override + public int getHeaderCacheSize() + { + return getHttpConfiguration().getHeaderCacheSize(); + } } \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java index 7ff4d5a2a47..912a51ee095 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java @@ -84,7 +84,7 @@ public class HttpChannelState } private final boolean DEBUG=LOG.isDebugEnabled(); - private final HttpChannel _channel; + private final HttpChannel _channel; private List _asyncListeners; private State _state; @@ -95,7 +95,7 @@ public class HttpChannelState private long _timeoutMs=DEFAULT_TIMEOUT; private AsyncContextEvent _event; - protected HttpChannelState(HttpChannel channel) + protected HttpChannelState(HttpChannel channel) { _channel=channel; _state=State.IDLE; @@ -626,7 +626,7 @@ public class HttpChannelState return _channel.getRequest(); } - public HttpChannel getHttpChannel() + public HttpChannel getHttpChannel() { return _channel; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 22a4326bd40..ca52fd28206 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -97,7 +97,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _connector = connector; _bufferPool = _connector.getByteBufferPool(); _generator = newHttpGenerator(); - HttpInput input = newHttpInput(); + HttpInput input = newHttpInput(); _channel = newHttpChannel(input); _parser = newHttpParser(); LOG.debug("New HTTP Connection {}", this); @@ -108,12 +108,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http return new HttpGenerator(_config.getSendServerVersion(),_config.getSendXPoweredBy()); } - protected HttpInput newHttpInput() + protected HttpInput newHttpInput() { return new HttpInputOverHTTP(this); } - protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) + protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) { return new HttpChannelOverHttp(this, _connector, _config, getEndPoint(), this, httpInput); } @@ -123,7 +123,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http return new HttpParser(newRequestHandler(), getHttpConfiguration().getRequestHeaderSize()); } - protected HttpParser.RequestHandler newRequestHandler() + protected HttpParser.RequestHandler newRequestHandler() { return _channel; } @@ -138,7 +138,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http return _connector; } - public HttpChannel getHttpChannel() + public HttpChannel getHttpChannel() { return _channel; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java index 833ecdede7f..e0275c92a76 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java @@ -19,12 +19,15 @@ package org.eclipse.jetty.server; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.Objects; + import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.RuntimeIOException; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -36,10 +39,35 @@ import org.eclipse.jetty.util.log.Logger; * state that tells whether an EOF has arrived. * Only once the content has been consumed the content state is moved to the EOF state. */ -public abstract class HttpInput extends ServletInputStream implements Runnable +public abstract class HttpInput extends ServletInputStream implements Runnable { private final static Logger LOG = Log.getLogger(HttpInput.class); + public static class Content extends Callback.Adapter + { + private final ByteBuffer _content; + public Content(ByteBuffer content) + { + _content=content; + } + + public ByteBuffer getContent() + { + return _content; + } + + public boolean hasContent() + { + return _content.hasRemaining(); + } + + public int remaining() + { + return _content.remaining(); + } + + } + private final byte[] _oneByteBuffer = new byte[1]; private final Object _lock; private HttpChannelState _channelState; @@ -93,7 +121,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl { synchronized (lock()) { - T item = getNextContent(); + Content item = getNextContent(); return item == null ? 0 : remaining(item); } } @@ -115,7 +143,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl { synchronized (lock()) { - T item = getNextContent(); + Content item = getNextContent(); if (item == null) { _contentState.waitForContent(this); @@ -137,9 +165,9 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl * @throws IOException * @see #nextContent() */ - protected T getNextContent() throws IOException + protected Content getNextContent() throws IOException { - T content = nextContent(); + Content content = nextContent(); if (content == null) { synchronized (lock()) @@ -164,32 +192,48 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl * @return the content or null if none available. * @throws IOException if retrieving the content fails */ - protected abstract T nextContent() throws IOException; + protected abstract Content nextContent() throws IOException; /** * @param item the content * @return how many bytes remain in the given content */ - protected abstract int remaining(T item); + protected int remaining(Content item) + { + return item.remaining(); + } + /** * Copies the given content into the given byte buffer. * - * @param item the content to copy from + * @param content the content to copy from * @param buffer the buffer to copy into * @param offset the buffer offset to start copying from * @param length the space available in the buffer * @return the number of bytes actually copied */ - protected abstract int get(T item, byte[] buffer, int offset, int length); + protected int get(Content content, byte[] buffer, int offset, int length) + { + int l = Math.min(content.remaining(), length); + content.getContent().get(buffer, offset, l); + return l; + } /** * Consumes the given content. + * Calls the content succeeded if all content consumed. * - * @param item the content to consume + * @param content the content to consume * @param length the number of bytes to consume */ - protected abstract void consume(T item, int length); + protected void consume(Content content, int length) + { + ByteBuffer buffer = content.getContent(); + buffer.position(buffer.position()+length); + if (length>0 && !buffer.hasRemaining()) + content.succeeded(); + } /** * Blocks until some content or some end-of-file event arrives. @@ -203,7 +247,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl * * @param item the content to add */ - public abstract void content(T item); + public abstract void content(Content content); protected boolean onAsyncRead() { @@ -273,7 +317,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl { while (!isFinished()) { - T item = getNextContent(); + Content item = getNextContent(); if (item == null) _contentState.waitForContent(this); else @@ -387,7 +431,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl try { - T item = getNextContent(); + Content item = getNextContent(); available = item != null && remaining(item) > 0; } catch (Exception e) @@ -420,7 +464,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl protected static abstract class State { - public void waitForContent(HttpInput in) throws IOException + public void waitForContent(HttpInput in) throws IOException { } @@ -438,7 +482,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl protected static final State STREAM = new State() { @Override - public void waitForContent(HttpInput input) throws IOException + public void waitForContent(HttpInput input) throws IOException { input.blockForContent(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInputOverHTTP.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInputOverHTTP.java index 35524500492..6af5197a28d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInputOverHTTP.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInputOverHTTP.java @@ -27,13 +27,14 @@ import org.eclipse.jetty.util.SharedBlockingCallback; import org.eclipse.jetty.util.SharedBlockingCallback.Blocker; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.server.HttpInput.Content; -public class HttpInputOverHTTP extends HttpInput implements Callback +public class HttpInputOverHTTP extends HttpInput implements Callback { private static final Logger LOG = Log.getLogger(HttpInputOverHTTP.class); private final SharedBlockingCallback _readBlocker = new SharedBlockingCallback(); private final HttpConnection _httpConnection; - private ByteBuffer _content; + private Content _content; /** * @param httpConnection @@ -78,10 +79,10 @@ public class HttpInputOverHTTP extends HttpInput implements Callback } @Override - protected ByteBuffer nextContent() throws IOException + protected Content nextContent() throws IOException { // If we have some content available, return it - if (BufferUtil.hasContent(_content)) + if (_content!=null && _content.hasContent()) return _content; // No - then we are going to need to parse some more content @@ -89,37 +90,16 @@ public class HttpInputOverHTTP extends HttpInput implements Callback _httpConnection.parseContent(); // If we have some content available, return it - if (BufferUtil.hasContent(_content)) + if (_content!=null && _content.hasContent()) return _content; return null; - } @Override - protected int remaining(ByteBuffer item) + public void content(Content item) { - return item.remaining(); - } - - @Override - protected int get(ByteBuffer item, byte[] buffer, int offset, int length) - { - int l = Math.min(item.remaining(), length); - item.get(buffer, offset, l); - return l; - } - - @Override - protected void consume(ByteBuffer item, int length) - { - item.position(item.position()+length); - } - - @Override - public void content(ByteBuffer item) - { - if (BufferUtil.hasContent(_content)) + if (_content!=null && _content.hasContent()) throw new IllegalStateException(); _content=item; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index 7c0fd899a41..85af6f7a692 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -54,7 +54,7 @@ import org.eclipse.jetty.util.log.Logger; public class HttpOutput extends ServletOutputStream implements Runnable { private static Logger LOG = Log.getLogger(HttpOutput.class); - private final HttpChannel _channel; + private final HttpChannel _channel; private final SharedBlockingCallback _writeblock=new SharedBlockingCallback(); private long _written; private ByteBuffer _aggregate; @@ -77,14 +77,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable enum OutputState { OPEN, ASYNC, READY, PENDING, UNREADY, ERROR, CLOSED } private final AtomicReference _state=new AtomicReference<>(OutputState.OPEN); - public HttpOutput(HttpChannel channel) + public HttpOutput(HttpChannel channel) { _channel = channel; _bufferSize = _channel.getHttpConfiguration().getOutputBufferSize(); _commitSize=_bufferSize/4; } - public HttpChannel getHttpChannel() + public HttpChannel getHttpChannel() { return _channel; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java index 881fbfa0842..ce67222978e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java @@ -35,17 +35,17 @@ import org.eclipse.jetty.util.log.Logger; * To assist the caller, subclasses may override methods {@link #onAsyncRead()}, {@link #onContentConsumed(Object)} * that can be implemented so that the caller will know when buffers are queued and consumed. */ -public abstract class QueuedHttpInput extends HttpInput +public class QueuedHttpInput extends HttpInput { private final static Logger LOG = Log.getLogger(QueuedHttpInput.class); - private final ArrayQueue _inputQ = new ArrayQueue<>(lock()); + private final ArrayQueue _inputQ = new ArrayQueue<>(lock()); public QueuedHttpInput() { } - public void content(T item) + public void content(Content item) { // The buffer is not copied here. This relies on the caller not recycling the buffer // until the it is consumed. The onContentConsumed and onAllContentConsumed() callbacks are @@ -68,10 +68,10 @@ public abstract class QueuedHttpInput extends HttpInput { synchronized (lock()) { - T item = _inputQ.pollUnsafe(); + Content item = _inputQ.pollUnsafe(); while (item != null) { - onContentConsumed(item); + item.failed(null); item = _inputQ.pollUnsafe(); } super.recycle(); @@ -79,17 +79,16 @@ public abstract class QueuedHttpInput extends HttpInput } @Override - protected T nextContent() + protected Content nextContent() { synchronized (lock()) { // Items are removed only when they are fully consumed. - T item = _inputQ.peekUnsafe(); + Content item = _inputQ.peekUnsafe(); // Skip consumed items at the head of the queue. while (item != null && remaining(item) == 0) { _inputQ.pollUnsafe(); - onContentConsumed(item); LOG.debug("{} consumed {}", this, item); item = _inputQ.peekUnsafe(); } @@ -116,13 +115,6 @@ public abstract class QueuedHttpInput extends HttpInput } } - /** - * Callback that signals that the given content has been consumed. - * - * @param item the consumed content - */ - protected abstract void onContentConsumed(T item); - public void earlyEOF() { synchronized (lock()) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 8ab8c732626..cc8e52f82f0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -126,10 +126,10 @@ public class Request implements HttpServletRequest private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault()); private static final int __NONE = 0, _STREAM = 1, __READER = 2; - private final HttpChannel _channel; + private final HttpChannel _channel; private final HttpFields _fields=new HttpFields(); private final List _requestAttributeListeners=new ArrayList<>(); - private final HttpInput _input; + private final HttpInput _input; public static class MultiPartCleanerListener implements ServletRequestListener { @@ -209,7 +209,7 @@ public class Request implements HttpServletRequest private AsyncContextState _async; /* ------------------------------------------------------------ */ - public Request(HttpChannel channel, HttpInput input) + public Request(HttpChannel channel, HttpInput input) { _channel = channel; _input = input; @@ -222,7 +222,7 @@ public class Request implements HttpServletRequest } /* ------------------------------------------------------------ */ - public HttpInput getHttpInput() + public HttpInput getHttpInput() { return _input; } @@ -502,7 +502,7 @@ public class Request implements HttpServletRequest /** * @return Returns the connection. */ - public HttpChannel getHttpChannel() + public HttpChannel getHttpChannel() { return _channel; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 0408c8825ca..3b8d2aab425 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -108,7 +108,7 @@ public class Response implements HttpServletResponse */ public final static String HTTP_ONLY_COMMENT = "__HTTP_ONLY__"; - private final HttpChannel _channel; + private final HttpChannel _channel; private final HttpFields _fields = new HttpFields(); private final AtomicInteger _include = new AtomicInteger(); private HttpOutput _out; @@ -124,13 +124,13 @@ public class Response implements HttpServletResponse private long _contentLength = -1; - public Response(HttpChannel channel, HttpOutput out) + public Response(HttpChannel channel, HttpOutput out) { _channel = channel; _out = out; } - protected HttpChannel getHttpChannel() + protected HttpChannel getHttpChannel() { return _channel; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index b1437d6d98d..11726bb9304 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -442,7 +442,7 @@ public class Server extends HandlerWrapper implements Attributes * or after the entire request has been received (for short requests of known length), or * on the dispatch of an async request. */ - public void handle(HttpChannel connection) throws IOException, ServletException + public void handle(HttpChannel connection) throws IOException, ServletException { final String target=connection.getRequest().getPathInfo(); final Request request=connection.getRequest(); @@ -484,7 +484,7 @@ public class Server extends HandlerWrapper implements Attributes * or after the entire request has been received (for short requests of known length), or * on the dispatch of an async request. */ - public void handleAsync(HttpChannel connection) throws IOException, ServletException + public void handleAsync(HttpChannel connection) throws IOException, ServletException { final HttpChannelState state = connection.getRequest().getHttpChannelState(); final AsyncContextEvent event = state.getAsyncContextEvent(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java index 97a3ac8d43e..9d5ebb8efde 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java @@ -201,7 +201,7 @@ public class IPAccessHandler extends HandlerWrapper public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Get the real remote IP (not the one set by the forwarded headers (which may be forged)) - HttpChannel channel = baseRequest.getHttpChannel(); + HttpChannel channel = baseRequest.getHttpChannel(); if (channel!=null) { EndPoint endp=channel.getEndPoint(); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java index 7162da1d9c6..877c237bc0b 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java @@ -100,7 +100,7 @@ public class ExtendedServerTest extends HttpServerTestBase } @Override - protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) + protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) { return new HttpChannelOverHttp(this, getConnector(), getHttpConfiguration(), getEndPoint(), this, httpInput) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index bd1904655cb..1b7abc5dcd6 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -163,7 +163,7 @@ public class HttpConnectionTest public void testBadPathDotDotPath() throws Exception { String response=connector.getResponses("GET /ooops/../../path HTTP/1.0\nHost: localhost:80\n\n"); - checkContains(response,0,"HTTP/1.1 400 Bad Request"); + checkContains(response,0,"HTTP/1.1 400 Bad URI"); } @Test @@ -178,28 +178,28 @@ public class HttpConnectionTest public void testBadPathEncodedDotDotPath() throws Exception { String response=connector.getResponses("GET /ooops/%2e%2e/%2e%2e/path HTTP/1.0\nHost: localhost:80\n\n"); - checkContains(response,0,"HTTP/1.1 400 Bad Request"); + checkContains(response,0,"HTTP/1.1 400 Bad URI"); } @Test public void testBadDotDotPath() throws Exception { String response=connector.getResponses("GET ../path HTTP/1.0\nHost: localhost:80\n\n"); - checkContains(response,0,"HTTP/1.1 400 Bad Request"); + checkContains(response,0,"HTTP/1.1 400 Bad URI"); } @Test public void testBadSlashDotDotPath() throws Exception { String response=connector.getResponses("GET /../path HTTP/1.0\nHost: localhost:80\n\n"); - checkContains(response,0,"HTTP/1.1 400 Bad Request"); + checkContains(response,0,"HTTP/1.1 400 Bad URI"); } @Test public void testEncodedBadDotDotPath() throws Exception { String response=connector.getResponses("GET %2e%2e/path HTTP/1.0\nHost: localhost:80\n\n"); - checkContains(response,0,"HTTP/1.1 400 Bad Request"); + checkContains(response,0,"HTTP/1.1 400 Bad URI"); } @Test diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java index 5509a2050dc..0b02bc59a41 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.util.BufferUtil; @@ -43,16 +44,17 @@ public class HttpWriterTest { _bytes = BufferUtil.allocate(2048); - final ByteBufferPool bufferPool = new MappedByteBufferPool(); - HttpChannel channel = new HttpChannel(null,new HttpConfiguration(),null,null,new ByteBufferQueuedHttpInput()) + final ByteBufferPool pool = new ArrayByteBufferPool(); + + HttpChannel channel = new HttpChannel(null,new HttpConfiguration(),null,null,new QueuedHttpInput()) { @Override public ByteBufferPool getByteBufferPool() { - return bufferPool; + return pool; } }; - + _httpOut = new HttpOutput(channel) { @Override diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/QueuedHttpInputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/QueuedHttpInputTest.java index 864d1a98d39..6448b55fefb 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/QueuedHttpInputTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/QueuedHttpInputTest.java @@ -25,7 +25,7 @@ public class QueuedHttpInputTest @Test public void testNoContentMessageComplete() throws Exception { - ByteBufferQueuedHttpInput input = new ByteBufferQueuedHttpInput(); + QueuedHttpInput input = new QueuedHttpInput(); input.messageComplete(); input.getNextContent(); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 294c5ffc220..18a88f6e7fc 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.server; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -779,9 +781,9 @@ public class RequestTest "\n", 200, TimeUnit.MILLISECONDS ); - assertTrue(response.indexOf("200")>0); - assertFalse(response.indexOf("Connection: close")>0); - assertTrue(response.indexOf("Hello World")>0); + assertThat(response,containsString("200")); + assertThat(response,Matchers.not(containsString("Connection: close"))); + assertThat(response,containsString("Hello World")); response=_connector.getResponses( "GET / HTTP/1.1\n"+ @@ -789,9 +791,9 @@ public class RequestTest "Connection: close\n"+ "\n" ); - assertTrue(response.indexOf("200")>0); - assertTrue(response.indexOf("Connection: close")>0); - assertTrue(response.indexOf("Hello World")>0); + assertThat(response,containsString("200")); + assertThat(response,containsString("Connection: close")); + assertThat(response,containsString("Hello World")); response=_connector.getResponses( "GET / HTTP/1.1\n"+ @@ -800,18 +802,18 @@ public class RequestTest "\n" ); - assertTrue(response.indexOf("200")>0); - assertTrue(response.indexOf("Connection: close")>0); - assertTrue(response.indexOf("Hello World")>0); + assertThat(response,containsString("200")); + assertThat(response,containsString("Connection: close")); + assertThat(response,containsString("Hello World")); response=_connector.getResponses( "GET / HTTP/1.0\n"+ "Host: whatever\n"+ "\n" ); - assertTrue(response.indexOf("200")>0); - assertFalse(response.indexOf("Connection: close")>0); - assertTrue(response.indexOf("Hello World")>0); + assertThat(response,containsString("200")); + assertThat(response,not(containsString("Connection: close"))); + assertThat(response,containsString("Hello World")); response=_connector.getResponses( "GET / HTTP/1.0\n"+ @@ -819,8 +821,8 @@ public class RequestTest "Connection: Other, close\n"+ "\n" ); - assertTrue(response.indexOf("200")>0); - assertTrue(response.indexOf("Hello World")>0); + assertThat(response,containsString("200")); + assertThat(response,containsString("Hello World")); response=_connector.getResponses( "GET / HTTP/1.0\n"+ @@ -829,9 +831,9 @@ public class RequestTest "\n", 200, TimeUnit.MILLISECONDS ); - assertTrue(response.indexOf("200")>0); - assertTrue(response.indexOf("Connection: keep-alive")>0); - assertTrue(response.indexOf("Hello World")>0); + assertThat(response,containsString("200")); + assertThat(response,Matchers.containsString("Connection: keep-alive")); + assertThat(response,containsString("Hello World")); _handler._checker = new RequestTester() { @@ -851,9 +853,9 @@ public class RequestTest "\n", 200, TimeUnit.MILLISECONDS ); - assertTrue(response.indexOf("200")>0); - assertTrue(response.indexOf("Connection: TE,Other")>0); - assertTrue(response.indexOf("Hello World")>0); + assertThat(response,containsString("200")); + assertThat(response,containsString("Connection: TE,Other")); + assertThat(response,containsString("Hello World")); response=_connector.getResponses( "GET / HTTP/1.1\n"+ diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 6b5bb4d1c4e..3513fe98e0e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -66,7 +66,7 @@ import org.junit.Test; public class ResponseTest { private Server _server; - private HttpChannel _channel; + private HttpChannel _channel; @Before public void init() throws Exception @@ -80,8 +80,8 @@ public class ResponseTest _server.start(); AbstractEndPoint endp = new ByteArrayEndPoint(_scheduler, 5000); - ByteBufferQueuedHttpInput input = new ByteBufferQueuedHttpInput(); - _channel = new HttpChannel(connector, new HttpConfiguration(), endp, new HttpTransport() + QueuedHttpInput input = new QueuedHttpInput(); + _channel = new HttpChannel(connector, new HttpConfiguration(), endp, new HttpTransport() { @Override public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java index 6eb7c152aa3..d4d773cfa8b 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java @@ -364,7 +364,7 @@ public class AsyncGzipFilter extends UserAgentFilter implements GzipFactory request.setAttribute(ETAG,etag.substring(0,dd)+(etag.endsWith("\"")?"\"":"")); } - HttpChannel channel = HttpChannel.getCurrentHttpChannel(); + HttpChannel channel = HttpChannel.getCurrentHttpChannel(); HttpOutput out = channel.getResponse().getHttpOutput(); if (!(out instanceof GzipHttpOutput)) { diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java index 636eab2b53c..28e22421427 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java @@ -52,7 +52,7 @@ public class GzipHttpOutput extends HttpOutput private GzipFactory _factory; private ByteBuffer _buffer; - public GzipHttpOutput(HttpChannel channel) + public GzipHttpOutput(HttpChannel channel) { super(channel); } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index 304f71fb874..ae890100ff4 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -38,7 +38,7 @@ import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class HttpChannelOverSPDY extends HttpChannel +public class HttpChannelOverSPDY extends HttpChannel { private static final Logger LOG = Log.getLogger(HttpChannelOverSPDY.class); diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java index 3085ed18bc6..75714157800 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java @@ -21,7 +21,7 @@ package org.eclipse.jetty.spdy.server.http; import org.eclipse.jetty.server.QueuedHttpInput; import org.eclipse.jetty.spdy.api.DataInfo; -public class HttpInputOverSPDY extends QueuedHttpInput +public class HttpInputOverSPDY extends QueuedHttpInput { @Override protected int remaining(DataInfo item) From 25295456aef95974be68c36a09c228309d8aa8ef Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 17 Jun 2014 00:12:57 +0200 Subject: [PATCH 090/269] renamed HTTP/2.0 to HTTP/2 --- .../org/eclipse/jetty/http/HttpVersion.java | 4 ++-- .../http2/frames/HeadersGenerateParseTest.java | 4 ++-- .../frames/PushPromiseGenerateParseTest.java | 4 ++-- .../jetty/http2/hpack/MetaDataBuilder.java | 6 +++--- .../jetty/http2/hpack/HpackEncoderTest.java | 18 +++++++++--------- .../eclipse/jetty/http2/hpack/HpackTest.java | 4 ++-- .../http2/server/HttpTransportOverHTTP2.java | 4 ++-- .../jetty/http2/server/HTTP2ServerTest.java | 6 +++--- .../jetty/http2/server/Http2Server.java | 4 ++-- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java index eb889e56a32..ebeb5fddf92 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java @@ -31,7 +31,7 @@ public enum HttpVersion HTTP_0_9("HTTP/0.9",9), HTTP_1_0("HTTP/1.0",10), HTTP_1_1("HTTP/1.1",11), - HTTP_2_0("HTTP/2.0",20); + HTTP_2("HTTP/2",20); /* ------------------------------------------------------------ */ public final static Trie CACHE= new ArrayTrie(); @@ -74,7 +74,7 @@ public enum HttpVersion switch(bytes[position+7]) { case '0': - return HTTP_2_0; + return HTTP_2; } break; } diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 38aa07281a7..b9291a020ff 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -51,7 +51,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); @@ -105,7 +105,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index 7ebc775545c..17620380e61 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -52,7 +52,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); @@ -107,7 +107,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); final List frames = new ArrayList<>(); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 94f4c55c036..fe7b63a6f43 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -107,10 +107,10 @@ public class MetaDataBuilder HttpFields fields = _fields; _fields = new HttpFields(Math.max(10,fields.size()+5)); if (_method!=null) - return new MetaData.Request(HttpVersion.HTTP_2_0,_scheme,_method,_authority,_host,_port,_path,fields); + return new MetaData.Request(HttpVersion.HTTP_2,_scheme,_method,_authority,_host,_port,_path,fields); if (_status!=0) - return new MetaData.Response(HttpVersion.HTTP_2_0,_status,fields); - return new MetaData(HttpVersion.HTTP_2_0,fields); + return new MetaData.Response(HttpVersion.HTTP_2,_status,fields); + return new MetaData(HttpVersion.HTTP_2,fields); } finally { diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index fa5669c88fd..7ca1dd521ec 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -70,7 +70,7 @@ public class HpackEncoderTest // encode them ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,pos); // something was encoded! @@ -89,7 +89,7 @@ public class HpackEncoderTest // encode exact same fields again! BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // nothing should be encoded! @@ -112,7 +112,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -136,7 +136,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -163,7 +163,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -191,7 +191,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -225,7 +225,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -246,7 +246,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -258,7 +258,7 @@ public class HpackEncoderTest // encode again BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2_0,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index 63a1dff5306..a088cec5abc 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -46,7 +46,7 @@ public class HpackTest fields0.add(HttpHeader.SERVER,"jetty"); fields0.add(HttpHeader.SET_COOKIE,"abcdefghijklmnopqrstuvwxyz"); fields0.add("custom-key","custom-value"); - Response original0 = new Response(HttpVersion.HTTP_2_0,200,fields0); + Response original0 = new Response(HttpVersion.HTTP_2,200,fields0); BufferUtil.clearToFill(buffer); encoder.encode(buffer,original0); @@ -68,7 +68,7 @@ public class HpackTest fields1.add(HttpHeader.CONTENT_LENGTH,"1234"); fields1.add(HttpHeader.SERVER,"jetty"); fields1.add("custom-key","other-value"); - Response original1 = new Response(HttpVersion.HTTP_2_0,200,fields1); + Response original1 = new Response(HttpVersion.HTTP_2,200,fields1); // Same again? BufferUtil.clearToFill(buffer); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 8f3fcd6dd59..9beebceb946 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -82,10 +82,10 @@ public class HttpTransportOverHTTP2 implements HttpTransport if (LOG.isDebugEnabled()) { LOG.debug("HTTP2 Response #{}:{}{} {}{}{}", - stream.getId(), System.lineSeparator(), HttpVersion.HTTP_2_0, info.getStatus(), System.lineSeparator(), info.getHttpFields()); + stream.getId(), System.lineSeparator(), HttpVersion.HTTP_2, info.getStatus(), System.lineSeparator(), info.getHttpFields()); } - MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2_0, info.getStatus(), info.getHttpFields()); + MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2, info.getStatus(), info.getHttpFields()); HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, endStream); stream.headers(frame, callback); } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 2869c3b9350..7405d9aac51 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -105,7 +105,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -154,7 +154,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0, HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -217,7 +217,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2_0,HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2,HttpScheme.HTTP, HttpMethod.GET.asString(), host + ":" + port, host, port, path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java index e5965e2d50f..35eb759dc2d 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java @@ -94,7 +94,7 @@ public class Http2Server // SSL Factory SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol()); - // SPDY Connector + // HTTP2 Connector ServerConnector http2Connector = new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config)); http2Connector.setPort(8443); @@ -118,7 +118,7 @@ public class Http2Server HttpSession session = request.getSession(true); response.setHeader("custom","value"); response.setContentType("text/plain"); - String content = "Hello from Jetty HTTP2\n"; + String content = "Hello from Jetty using "+request.getProtocol() +"\n"; content+="uri="+request.getRequestURI()+"\n"; content+="session="+session.getId()+(session.isNew()?"(New)\n":"\n"); content+="date="+new Date()+"\n"; From 31b7f0a59277555a74e8efceaa55d74d5e21be06 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 17 Jun 2014 09:28:50 +0200 Subject: [PATCH 091/269] Fixed references to MetaData, that has been moved to the jetty-http module. --- .../eclipse/jetty/http2/client/AbstractTest.java | 5 +++-- .../eclipse/jetty/http2/client/FlowControlTest.java | 13 +++++++------ .../org/eclipse/jetty/http2/client/HTTP2Test.java | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java index 54b7ce48cba..ac48a66db52 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -24,9 +24,10 @@ import javax.servlet.http.HttpServlet; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.server.ServerSessionListener; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory; @@ -105,6 +106,6 @@ public class AbstractTest String host = "localhost"; int port = connector.getLocalPort(); String authority = host + ":" + port; - return new MetaData.Request(HttpScheme.HTTP, method, authority, host, port, path, fields); + return new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, method, authority, host, port, path, fields); } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index 5f34b0cf76e..5d02bad399c 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -30,13 +30,14 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; @@ -71,7 +72,7 @@ public class FlowControlTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { HttpFields fields = new HttpFields(); - MetaData.Response response = new MetaData.Response(200, fields); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, fields); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -149,7 +150,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new MetaData.Response(200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -241,7 +242,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new MetaData.Response(200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return new Stream.Listener.Adapter() @@ -346,7 +347,7 @@ public class FlowControlTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { // For every stream, send down half the window size of data. - MetaData.Response metaData = new MetaData.Response(200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(windowSize / 2), true); @@ -428,7 +429,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new MetaData.Response(200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.wrap(data), true); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index 4e7e91d5254..e68bbf00c02 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -29,11 +29,11 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; -import org.eclipse.jetty.http2.hpack.MetaData; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.junit.Assert; From 20c38c2396dfc6bc7ee3ffc53d2af02d3411da7e Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 17 Jun 2014 10:53:00 +0200 Subject: [PATCH 092/269] Cosmetics. --- .../src/main/java/org/eclipse/jetty/server/HttpChannel.java | 4 +--- .../main/java/org/eclipse/jetty/server/QueuedHttpInput.java | 5 +++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index c39721a9e1e..5a70c09cbca 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -25,7 +25,6 @@ import java.nio.channels.ClosedChannelException; import java.nio.charset.StandardCharsets; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; @@ -37,7 +36,6 @@ import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator.ResponseInfo; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; -import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; @@ -543,7 +541,7 @@ public class HttpChannel implements Runnable if (LOG.isDebugEnabled()) LOG.debug("{} content {}", this, content); - HttpInput input = (HttpInput)_request.getHttpInput(); + HttpInput input = _request.getHttpInput(); input.content(content); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java index ce67222978e..a5646323146 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java @@ -26,13 +26,14 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /** - * {@link QueuedHttpInput} holds a queue of items passed to it by calls to {@link #content(Object)}. + * {@link QueuedHttpInput} holds a queue of items passed to it by calls to {@link #content(HttpInput.Content)}. *

* {@link QueuedHttpInput} stores the items directly; if the items contain byte buffers, it does not copy them * but simply holds references to the item, thus the caller must organize for those buffers to valid while * held by this class. *

- * To assist the caller, subclasses may override methods {@link #onAsyncRead()}, {@link #onContentConsumed(Object)} + * To assist the caller, subclasses may override methods such as {@link #onAsyncRead()}, + * {@link #consume(HttpInput.Content, int)}, etc. * that can be implemented so that the caller will know when buffers are queued and consumed. */ public class QueuedHttpInput extends HttpInput From aafed9230581f40cd52765366d89ea302fdd2c45 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 17 Jun 2014 10:53:20 +0200 Subject: [PATCH 093/269] Updated SPDY code to HttpChannel refactorings. --- .../spdy/server/http/HttpChannelOverSPDY.java | 150 ++++++------------ .../spdy/server/http/HttpInputOverSPDY.java | 28 ++-- .../server/proxy/ProxyHTTPSPDYConnection.java | 10 +- 3 files changed, 61 insertions(+), 127 deletions(-) diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index ae890100ff4..a3042874547 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -21,19 +21,20 @@ package org.eclipse.jetty.spdy.server.http; import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpTransport; -import org.eclipse.jetty.spdy.api.ByteBufferDataInfo; import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.Stream; import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -43,9 +44,6 @@ public class HttpChannelOverSPDY extends HttpChannel private static final Logger LOG = Log.getLogger(HttpChannelOverSPDY.class); private final Stream stream; - private boolean dispatched; // Guarded by synchronization on tasks - private boolean redispatch; // Guarded by synchronization on tasks - private boolean headersComplete; public HttpChannelOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInputOverSPDY input, Stream stream) { @@ -53,54 +51,6 @@ public class HttpChannelOverSPDY extends HttpChannel this.stream = stream; } - @Override - public boolean headerComplete() - { - headersComplete = true; - return super.headerComplete(); - } - - private void dispatch() - { - synchronized (this) - { - if (dispatched) - redispatch=true; - else - { - LOG.debug("Dispatch {}", this); - dispatched=true; - execute(this); - } - } - } - - @Override - public void run() - { - boolean execute=true; - - while(execute) - { - try - { - LOG.debug("Executing {}",this); - super.run(); - } - finally - { - LOG.debug("Completing {}", this); - synchronized (this) - { - dispatched = redispatch; - redispatch=false; - execute=dispatched; - } - } - } - } - - public void requestStart(final Fields headers, final boolean endRequest) { if (!headers.isEmpty()) @@ -109,63 +59,34 @@ public class HttpChannelOverSPDY extends HttpChannel public void requestHeaders(Fields headers, boolean endRequest) { - boolean proceed = performBeginRequest(headers); + boolean proceed = performRequest(headers); if (!proceed) return; - performHeaders(headers); - if (endRequest) - { - boolean dispatch = headerComplete(); - if (messageComplete()) - dispatch=true; - if (dispatch) - dispatch(); - } + onRequestComplete(); + + execute(this); } public void requestContent(final DataInfo dataInfo, boolean endRequest) { - boolean dispatch=false; - if (!headersComplete && headerComplete()) - dispatch=true; - LOG.debug("HTTP > {} bytes of content", dataInfo.length()); // We need to copy the dataInfo since we do not know when its bytes // will be consumed. When the copy is consumed, we consume also the // original, so the implementation can send a window update. ByteBuffer copyByteBuffer = dataInfo.asByteBuffer(false); - ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(copyByteBuffer, dataInfo.isClose()) - { - @Override - public void consume(int delta) - { - super.consume(delta); - dataInfo.consume(delta); - } - }; - LOG.debug("Queuing last={} content {}", endRequest, copyDataInfo); - if (content(copyDataInfo)) - dispatch=true; + HttpInputOverSPDY.ContentOverSPDY content = new HttpInputOverSPDY.ContentOverSPDY(copyByteBuffer, dataInfo); - if (endRequest && messageComplete()) - dispatch=true; - - if (dispatch) - dispatch(); + onContent(content); + + if (endRequest) + onRequestComplete(); } - @Override - public boolean messageComplete() - { - super.messageComplete(); - return false; - } - - private boolean performBeginRequest(Fields headers) + private boolean performRequest(Fields headers) { short version = stream.getSession().getVersion(); Fields.Field methodHeader = headers.get(HTTPSPDYHeader.METHOD.name(version)); @@ -174,7 +95,7 @@ public class HttpChannelOverSPDY extends HttpChannel if (methodHeader == null || uriHeader == null || versionHeader == null) { - badMessage(400, "Missing required request line elements"); + onBadMessage(400, "Missing required request line elements"); return false; } @@ -184,16 +105,17 @@ public class HttpChannelOverSPDY extends HttpChannel HttpURI uri = new HttpURI(uriHeader.getValue()); LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion); - startRequest(methodHeader.getValue(), uri, httpVersion); + String scheme = "http"; Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version)); if (schemeHeader != null) - getRequest().setScheme(schemeHeader.getValue()); - return true; - } + { + scheme = schemeHeader.getValue(); + getRequest().setScheme(scheme); + } - private void performHeaders(Fields headers) - { + String authority = null; + HttpFields fields = new HttpFields(); for (Fields.Field header : headers) { String name = header.getName(); @@ -202,10 +124,11 @@ public class HttpChannelOverSPDY extends HttpChannel HTTPSPDYHeader specialHeader = HTTPSPDYHeader.from(stream.getSession().getVersion(), name); if (specialHeader != null) { - if (specialHeader == HTTPSPDYHeader.HOST) - name = "host"; - else + if (specialHeader != HTTPSPDYHeader.HOST) continue; + + name = "host"; + authority = header.getValue(); } switch (name) @@ -223,10 +146,31 @@ public class HttpChannelOverSPDY extends HttpChannel // Spec says headers must be single valued String value = header.getValue(); LOG.debug("HTTP > {}: {}", name, value); - parsedHeader(new HttpField(name,value)); + fields.add(new HttpField(name, value)); break; } } } + + String host = null; + int port = 0; + if (authority != null) + { + int colon = authority.indexOf(':'); + if (colon > 0) + { + host = authority.substring(0, colon); + port = Integer.valueOf(authority.substring(colon + 1)); + } + else + { + host = authority; + port = HttpScheme.HTTPS.is(scheme) ? 443 : 80; + } + } + + MetaData.Request request = new MetaData.Request(httpVersion, httpMethod.asString(), uri, fields, host, port); + onRequest(request); + return true; } } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java index 75714157800..bd57e2726f8 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java @@ -18,32 +18,28 @@ package org.eclipse.jetty.spdy.server.http; +import java.nio.ByteBuffer; + import org.eclipse.jetty.server.QueuedHttpInput; import org.eclipse.jetty.spdy.api.DataInfo; public class HttpInputOverSPDY extends QueuedHttpInput { @Override - protected int remaining(DataInfo item) + protected void consume(Content content, int length) { - return item.available(); + ContentOverSPDY spdyContent = (ContentOverSPDY)content; + spdyContent.dataInfo.consume(length); } - @Override - protected int get(DataInfo item, byte[] buffer, int offset, int length) + protected static class ContentOverSPDY extends Content { - return item.readInto(buffer, offset, length); - } - - @Override - protected void consume(DataInfo item, int length) - { - item.consume(length); - } + private final DataInfo dataInfo; - @Override - protected void onContentConsumed(DataInfo dataInfo) - { - dataInfo.consume(dataInfo.length()); + protected ContentOverSPDY(ByteBuffer content, DataInfo dataInfo) + { + super(content); + this.dataInfo = dataInfo; + } } } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java index 6a6ba1fad28..d4a5d84a434 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java @@ -53,12 +53,11 @@ import org.eclipse.jetty.spdy.api.Stream; import org.eclipse.jetty.spdy.api.StreamFrameListener; import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Promise; -public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParser.RequestHandler +public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParser.RequestHandler { private final short version; private final Fields headers = new Fields(); @@ -76,7 +75,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse } @Override - protected HttpParser.RequestHandler newRequestHandler() + protected HttpParser.RequestHandler newRequestHandler() { return this; } @@ -102,11 +101,6 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse headers.put(field.getName(), field.getValue()); } - @Override - public void parsedHostHeader(String host, int port) - { - } - @Override public boolean headerComplete() { From 4c2a3dfbe6d9ab3fa9f6dc29598563377fedd1eb Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 17 Jun 2014 11:03:27 +0200 Subject: [PATCH 094/269] better hpack debug --- .../test/resources/jetty-logging.properties | 10 +++++++ .../jetty/http2/hpack/HpackContext.java | 30 ++++++++++++------- .../jetty/http2/hpack/HpackDecoder.java | 4 ++- .../jetty/http2/hpack/HpackEncoder.java | 3 ++ 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 jetty-http2/http2-common/src/test/resources/jetty-logging.properties diff --git a/jetty-http2/http2-common/src/test/resources/jetty-logging.properties b/jetty-http2/http2-common/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..31b37987e9a --- /dev/null +++ b/jetty-http2/http2-common/src/test/resources/jetty-logging.properties @@ -0,0 +1,10 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.LEVEL=INFO +org.eclipse.jetty.STACKS=true +org.eclipse.jetty.SOURCE=false +org.eclipse.jetty.http2.hpack.LEVEL=debug +#org.eclipse.jetty.spdy.LEVEL=DEBUG +#org.eclipse.jetty.server.LEVEL=DEBUG +#org.eclipse.jetty.io.LEVEL=DEBUG +#org.eclipse.jetty.io.ssl.LEVEL=DEBUG +#org.eclipse.jetty.spdy.server.LEVEL=DEBUG diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 846ab01cda7..9e1af505991 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -179,17 +179,19 @@ public class HpackContext } }; - HpackContext(int maxHeaderTableSize) { _maxHeaderTableSizeInBytes=maxHeaderTableSize; int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10); _headerTable=new HeaderTable(guesstimateEntries,guesstimateEntries+10); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("HdrTbl[%x] created max=%d",hashCode(),maxHeaderTableSize)); } public void resize(int newMaxHeaderTableSize) { - LOG.debug("HdrTbl resized {}",newMaxHeaderTableSize); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("HdrTbl[%x] resized max=%d->%d",hashCode(),_maxHeaderTableSizeInBytes,newMaxHeaderTableSize)); _maxHeaderTableSizeInBytes=newMaxHeaderTableSize; int guesstimateEntries = 10+newMaxHeaderTableSize/(32+10+10); evict(); @@ -232,7 +234,8 @@ public class HpackContext int size = entry.getSize(); if (size>_maxHeaderTableSizeInBytes) { - LOG.debug("!added {} too big",field); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("HdrTbl[%x] !added size %d>%d",hashCode(),size,_maxHeaderTableSizeInBytes)); return null; } _headerTableSizeInBytes+=size; @@ -240,7 +243,8 @@ public class HpackContext _fieldMap.put(field,entry); _nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry); - LOG.debug("HdrTbl added {}",entry); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("HdrTbl[%x] added %s",hashCode(),entry)); evict(); return entry; } @@ -290,7 +294,8 @@ public class HpackContext public void clearReferenceSet() { - LOG.debug("RefSet cleared"); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("RefSet[%x] cleared",hashCode())); Entry entry = _refSet._refSetNext; while(entry!=_refSet) { @@ -312,7 +317,8 @@ public class HpackContext entry._used=false; else { - LOG.debug("RefSet remove unused {}",entry); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("RefSet[%x] remove unused",hashCode(),entry)); // encode the reference to remove it buffer.put((byte)0x80); NBitInteger.encode(buffer,7,index(entry)); @@ -331,7 +337,8 @@ public class HpackContext entry._used=false; else { - LOG.debug("RefSet emit unused {}",entry); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("RefSet[%x] emit unref",hashCode(),entry)); builder.emit(entry.getHttpField()); } @@ -378,7 +385,8 @@ public class HpackContext while (_headerTableSizeInBytes>_maxHeaderTableSizeInBytes) { Entry entry = _headerTable.pollUnsafe(); - LOG.debug("HdrTbl evict {}",entry); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("HdrTbl[%x] evict %s",hashCode(),entry)); _headerTableSizeInBytes-=entry.getSize(); entry.removeFromRefSet(); entry._index=-1; @@ -497,7 +505,8 @@ public class HpackContext _refSetPrev=ctx._refSet._refSetPrev; ctx._refSet._refSetPrev._refSetNext=this; ctx._refSet._refSetPrev=this; - LOG.debug("RefSet added {}",this); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("RefSet[%x] added",ctx.hashCode(),this)); } public boolean isInReferenceSet() @@ -507,7 +516,8 @@ public class HpackContext public void removeFromRefSet() { - LOG.debug("RefSet remove {}",this); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("RefSet[?] remove %s",this)); if (_refSetNext!=this) { _refSetNext._refSetPrev=_refSetPrev; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index fa7fbe08eb2..e74f80e8931 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -63,10 +63,12 @@ public class HpackDecoder public MetaData decode(ByteBuffer buffer) { + if (LOG.isDebugEnabled()) + LOG.debug(String.format("CtxTbl[%x] decoding",_context.hashCode())); while(buffer.hasRemaining()) { if (LOG.isDebugEnabled()) - { + { int l=Math.min(buffer.remaining(),16); LOG.debug("decode "+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l)+(l Date: Tue, 17 Jun 2014 11:04:08 +0200 Subject: [PATCH 095/269] Fixed tests to make the generator and the parser have the same scope. --- .../test/resources/jetty-logging.properties | 2 +- .../http2/frames/DataGenerateParseTest.java | 30 +++++------ .../http2/frames/GoAwayGenerateParseTest.java | 36 ++++++------- .../frames/HeadersGenerateParseTest.java | 42 +++++++-------- .../http2/frames/PingGenerateParseTest.java | 32 ++++++------ .../frames/PriorityGenerateParseTest.java | 36 ++++++------- .../frames/PushPromiseGenerateParseTest.java | 44 ++++++++-------- .../http2/frames/ResetGenerateParseTest.java | 32 ++++++------ .../frames/SettingsGenerateParseTest.java | 51 ++++++++++--------- .../frames/WindowUpdateGenerateParseTest.java | 32 ++++++------ .../test/resources/jetty-logging.properties | 3 +- 11 files changed, 176 insertions(+), 164 deletions(-) diff --git a/jetty-http2/http2-client/src/test/resources/jetty-logging.properties b/jetty-http2/http2-client/src/test/resources/jetty-logging.properties index 13ddd0bba9d..b4e43807801 100644 --- a/jetty-http2/http2-client/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-client/src/test/resources/jetty-logging.properties @@ -1,2 +1,2 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.http2.LEVEL=DEBUG +org.eclipse.jetty.http2.LEVEL=INFO diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 3e77b30991c..8a635177c32 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -89,23 +89,23 @@ public class DataGenerateParseTest { DataGenerator generator = new DataGenerator(new HeaderGenerator()); - // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onData(DataFrame frame) + { + frames.add(frame); + return false; + } + }); + + // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateData(lease, 13, data.slice(), true, data.remaining()); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onData(DataFrame frame) - { - frames.add(frame); - return false; - } - }); - frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) { @@ -121,10 +121,6 @@ public class DataGenerateParseTest { DataGenerator generator = new DataGenerator(new HeaderGenerator()); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - ByteBuffer data = ByteBuffer.wrap(largeContent); - generator.generateData(lease, 13, data.slice(), true, data.remaining()); - final List frames = new ArrayList<>(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @@ -136,6 +132,10 @@ public class DataGenerateParseTest } }); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + ByteBuffer data = ByteBuffer.wrap(largeContent); + generator.generateData(lease, 13, data.slice(), true, data.remaining()); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java index e152dbf3753..dfe80d727f4 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java @@ -40,24 +40,25 @@ public class GoAwayGenerateParseTest { GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator()); + final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onGoAway(GoAwayFrame frame) + { + frames.add(frame); + return false; + } + }); + int lastStreamId = 13; int error = 17; // Iterate a few times to be sure generator and parser are properly reset. - final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateGoAway(lease, lastStreamId, error, null); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onGoAway(GoAwayFrame frame) - { - frames.add(frame); - return false; - } - }); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -81,14 +82,7 @@ public class GoAwayGenerateParseTest { GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator()); - int lastStreamId = 13; - int error = 17; - byte[] payload = new byte[16]; - new Random().nextBytes(payload); - final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateGoAway(lease, lastStreamId, error, payload); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -99,6 +93,14 @@ public class GoAwayGenerateParseTest } }); + int lastStreamId = 13; + int error = 17; + byte[] payload = new byte[16]; + new Random().nextBytes(payload); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateGoAway(lease, lastStreamId, error, payload); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index b9291a020ff..0ff62a23d65 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -26,22 +26,20 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.HeadersGenerator; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; public class HeadersGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); - @Ignore @Test public void testGenerateParse() throws Exception { @@ -53,21 +51,22 @@ public class HeadersGenerateParseTest fields.put("User-Agent", "Jetty"); MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); - // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onHeaders(HeadersFrame frame) + { + frames.add(frame); + return false; + } + }); + + // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateHeaders(lease, streamId, metaData, false); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onHeaders(HeadersFrame frame) - { - frames.add(frame); - return false; - } - }); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -101,15 +100,7 @@ public class HeadersGenerateParseTest { HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder()); - int streamId = 13; - HttpFields fields = new HttpFields(); - fields.put("Accept", "text/html"); - fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); - final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateHeaders(lease, streamId, metaData, false); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -120,6 +111,15 @@ public class HeadersGenerateParseTest } }); + int streamId = 13; + HttpFields fields = new HttpFields(); + fields.put("Accept", "text/html"); + fields.put("User-Agent", "Jetty"); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateHeaders(lease, streamId, metaData, false); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java index b0ecb82b544..b61a12fc5c5 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -40,24 +40,25 @@ public class PingGenerateParseTest { PingGenerator generator = new PingGenerator(new HeaderGenerator()); + final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onPing(PingFrame frame) + { + frames.add(frame); + return false; + } + }); + byte[] payload = new byte[8]; new Random().nextBytes(payload); // Iterate a few times to be sure generator and parser are properly reset. - final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generatePing(lease, payload, true); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onPing(PingFrame frame) - { - frames.add(frame); - return false; - } - }); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -80,12 +81,7 @@ public class PingGenerateParseTest { PingGenerator generator = new PingGenerator(new HeaderGenerator()); - byte[] payload = new byte[8]; - new Random().nextBytes(payload); - final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generatePing(lease, payload, true); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -96,6 +92,12 @@ public class PingGenerateParseTest } }); + byte[] payload = new byte[8]; + new Random().nextBytes(payload); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePing(lease, payload, true); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index b6a93f55647..9a107a3edce 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -39,26 +39,27 @@ public class PriorityGenerateParseTest { PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator()); + final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onPriority(PriorityFrame frame) + { + frames.add(frame); + return false; + } + }); + int streamId = 13; int dependentStreamId = 17; int weight = 3; boolean exclusive = true; // Iterate a few times to be sure generator and parser are properly reset. - final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generatePriority(lease, streamId, dependentStreamId, weight, exclusive); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onPriority(PriorityFrame frame) - { - frames.add(frame); - return false; - } - }); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -83,14 +84,7 @@ public class PriorityGenerateParseTest { PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator()); - int streamId = 13; - int dependentStreamId = 17; - int weight = 3; - boolean exclusive = true; - final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generatePriority(lease, streamId, dependentStreamId, weight, exclusive); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -101,6 +95,14 @@ public class PriorityGenerateParseTest } }); + int streamId = 13; + int dependentStreamId = 17; + int weight = 3; + boolean exclusive = true; + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePriority(lease, streamId, dependentStreamId, weight, exclusive); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index 17620380e61..60b14a73d1e 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -26,27 +26,36 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.PushPromiseGenerator; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; public class PushPromiseGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); - @Ignore @Test public void testGenerateParse() throws Exception { PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder()); + final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onPushPromise(PushPromiseFrame frame) + { + frames.add(frame); + return false; + } + }); + int streamId = 13; int promisedStreamId = 17; HttpFields fields = new HttpFields(); @@ -55,20 +64,10 @@ public class PushPromiseGenerateParseTest MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); // Iterate a few times to be sure generator and parser are properly reset. - final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generatePushPromise(lease, streamId, promisedStreamId, metaData); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onPushPromise(PushPromiseFrame frame) - { - frames.add(frame); - return false; - } - }); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -102,16 +101,7 @@ public class PushPromiseGenerateParseTest { PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder()); - int streamId = 13; - int promisedStreamId = 17; - HttpFields fields = new HttpFields(); - fields.put("Accept", "text/html"); - fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); - final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generatePushPromise(lease, streamId, promisedStreamId, metaData); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -122,6 +112,16 @@ public class PushPromiseGenerateParseTest } }); + int streamId = 13; + int promisedStreamId = 17; + HttpFields fields = new HttpFields(); + fields.put("Accept", "text/html"); + fields.put("User-Agent", "Jetty"); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generatePushPromise(lease, streamId, promisedStreamId, metaData); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index 05cc77661d5..503992ddcda 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -39,24 +39,25 @@ public class ResetGenerateParseTest { ResetGenerator generator = new ResetGenerator(new HeaderGenerator()); + final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onReset(ResetFrame frame) + { + frames.add(frame); + return false; + } + }); + int streamId = 13; int error = 17; // Iterate a few times to be sure generator and parser are properly reset. - final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateReset(lease, streamId, error); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onReset(ResetFrame frame) - { - frames.add(frame); - return false; - } - }); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -79,12 +80,7 @@ public class ResetGenerateParseTest { ResetGenerator generator = new ResetGenerator(new HeaderGenerator()); - int streamId = 13; - int error = 17; - final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateReset(lease, streamId, error); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -95,6 +91,12 @@ public class ResetGenerateParseTest } }); + int streamId = 13; + int error = 17; + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateReset(lease, streamId, error); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index 381a1ddf664..a37c0d86057 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -72,21 +72,22 @@ public class SettingsGenerateParseTest { SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); - // Iterate a few times to be sure generator and parser are properly reset. final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onSettings(SettingsFrame frame) + { + frames.add(frame); + return false; + } + }); + + // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateSettings(lease, settings, true); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onSettings(SettingsFrame frame) - { - frames.add(frame); - return false; - } - }); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -105,13 +106,6 @@ public class SettingsGenerateParseTest public void testGenerateParseInvalidSettings() throws Exception { SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); - Map settings1 = new HashMap<>(); - settings1.put(13, 17); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings1, true); - // Modify the length of the frame to make it invalid - ByteBuffer bytes = lease.getByteBuffers().get(0); - bytes.putShort(0, (short)(bytes.getShort(0) - 1)); final AtomicInteger errorRef = new AtomicInteger(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() @@ -123,6 +117,14 @@ public class SettingsGenerateParseTest } }); + Map settings1 = new HashMap<>(); + settings1.put(13, 17); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateSettings(lease, settings1, true); + // Modify the length of the frame to make it invalid + ByteBuffer bytes = lease.getByteBuffers().get(0); + bytes.putShort(0, (short)(bytes.getShort(0) - 1)); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) @@ -139,14 +141,7 @@ public class SettingsGenerateParseTest { SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); - Map settings1 = new HashMap<>(); - int key = 13; - Integer value = 17; - settings1.put(key, value); - final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings1, true); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -157,6 +152,14 @@ public class SettingsGenerateParseTest } }); + Map settings1 = new HashMap<>(); + int key = 13; + Integer value = 17; + settings1.put(key, value); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateSettings(lease, settings1, true); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java index ea7095628b8..3a8ef8dc07f 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java @@ -39,24 +39,25 @@ public class WindowUpdateGenerateParseTest { WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator()); + final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onWindowUpdate(WindowUpdateFrame frame) + { + frames.add(frame); + return false; + } + }); + int streamId = 13; int windowUpdate = 17; // Iterate a few times to be sure generator and parser are properly reset. - final List frames = new ArrayList<>(); for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateWindowUpdate(lease, streamId, windowUpdate); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() - { - @Override - public boolean onWindowUpdate(WindowUpdateFrame frame) - { - frames.add(frame); - return false; - } - }); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -79,12 +80,7 @@ public class WindowUpdateGenerateParseTest { WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator()); - int streamId = 13; - int windowUpdate = 17; - final List frames = new ArrayList<>(); - ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateWindowUpdate(lease, streamId, windowUpdate); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() { @Override @@ -95,6 +91,12 @@ public class WindowUpdateGenerateParseTest } }); + int streamId = 13; + int windowUpdate = 17; + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateWindowUpdate(lease, streamId, windowUpdate); + for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) diff --git a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties index 292f2fc6550..b4e43807801 100644 --- a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties @@ -1,3 +1,2 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.http2.LEVEL=DEBUG -org.eclipse.jetty.spdy.server.LEVEL=DEBUG +org.eclipse.jetty.http2.LEVEL=INFO From 0539b48b8a9311e56e99568758f798b83c2ff0f0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 17 Jun 2014 15:28:40 +0200 Subject: [PATCH 096/269] nicer constructors --- .../eclipse/jetty/http/HostPortHttpField.java | 10 +++++ .../org/eclipse/jetty/server/Request.java | 41 +------------------ .../org/eclipse/jetty/server/RequestTest.java | 2 +- .../eclipse/jetty/servlet/ServletHolder.java | 3 +- 4 files changed, 15 insertions(+), 41 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java index 11c233cd4f7..0ce2ccd4561 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java @@ -30,6 +30,16 @@ public class HostPortHttpField extends HttpField { public final String _host; public final int _port; + + public HostPortHttpField(String authority) + { + this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority); + } + + public HostPortHttpField(HttpHeader header, String authority) + { + this(header,header.asString(),authority); + } public HostPortHttpField(HttpHeader header, String name, String authority) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index cc8e52f82f0..9b09b8200a0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -40,6 +40,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; + import javax.servlet.AsyncContext; import javax.servlet.AsyncListener; import javax.servlet.DispatcherType; @@ -51,8 +52,6 @@ import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.ServletRequestEvent; -import javax.servlet.ServletRequestListener; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; @@ -75,7 +74,6 @@ import org.eclipse.jetty.server.session.AbstractSession; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiPartInputStreamParser; import org.eclipse.jetty.util.StringUtil; @@ -130,42 +128,6 @@ public class Request implements HttpServletRequest private final HttpFields _fields=new HttpFields(); private final List _requestAttributeListeners=new ArrayList<>(); private final HttpInput _input; - - public static class MultiPartCleanerListener implements ServletRequestListener - { - @Override - public void requestDestroyed(ServletRequestEvent sre) - { - //Clean up any tmp files created by MultiPartInputStream - MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(__MULTIPART_INPUT_STREAM); - if (mpis != null) - { - ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(__MULTIPART_CONTEXT); - - //Only do the cleanup if we are exiting from the context in which a servlet parsed the multipart files - if (context == sre.getServletContext()) - { - try - { - mpis.deleteParts(); - } - catch (MultiException e) - { - sre.getServletContext().log("Errors deleting multipart tmp files", e); - } - } - } - } - - @Override - public void requestInitialized(ServletRequestEvent sre) - { - //nothing to do, multipart config set up by ServletHolder.handle() - } - - } - - private boolean _secure; private boolean _asyncSupported = true; @@ -2259,4 +2221,5 @@ public class Request implements HttpServletRequest throw new ServletException(e); } } + } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 18a88f6e7fc..cf712a7bf16 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -194,7 +194,7 @@ public class RequestTest contextHandler.setContextPath("/foo"); contextHandler.setResourceBase("."); contextHandler.setHandler(new MultiPartRequestHandler(testTmpDir)); - contextHandler.addEventListener(new Request.MultiPartCleanerListener() + contextHandler.addEventListener(new MultiPartCleanerListener() { @Override diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java index 1df08b33dc6..cc6ed9d6cd4 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java @@ -45,6 +45,7 @@ import javax.servlet.UnavailableException; import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.RunAsToken; +import org.eclipse.jetty.server.MultiPartCleanerListener; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.handler.ContextHandler; @@ -665,7 +666,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope //servlet calling Request.getPart() or Request.getParts() ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext()); - ch.addEventListener(new Request.MultiPartCleanerListener()); + ch.addEventListener(new MultiPartCleanerListener()); } } From 85cb290e1c69c4ba5df04df8ee5ab433fe099719 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 17 Jun 2014 15:39:55 +0200 Subject: [PATCH 097/269] minor clean ups --- .../eclipse/jetty/http/HostPortHttpField.java | 2 - .../org/eclipse/jetty/http/HttpFields.java | 7 ++- .../org/eclipse/jetty/server/HttpChannel.java | 26 +------- .../server/MultiPartCleanerListener.java | 61 +++++++++++++++++++ .../org/eclipse/jetty/server/Request.java | 12 +++- 5 files changed, 79 insertions(+), 29 deletions(-) create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java index 0ce2ccd4561..4b8013ca726 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java @@ -107,6 +107,4 @@ public class HostPortHttpField extends HttpField { return _port; } - - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 98327caea2d..c0a674bb630 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -600,7 +600,12 @@ public class HttpFields implements Iterable { _fields.add(field); } - + + public void addAll(HttpFields fields) + { + _fields.addAll(fields._fields); + } + /** * Add fields from another HttpFields instance. Single valued fields are replaced, while all * others are added. diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 5a70c09cbca..d73d73ebc63 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -478,7 +478,6 @@ public class HttpChannel implements Runnable _request.setUri(request.getURI()); - String path; try { @@ -505,31 +504,8 @@ public class HttpChannel implements Runnable } _request.setPathInfo(info); - // TODO avoid playing in headers - for (HttpField field : request.getFields()) - { - HttpHeader header=field.getHeader(); - String value=field.getValue(); - if (value == null) - value = ""; - if (header != null) - { - switch (header) - { - case CONTENT_TYPE: - MimeTypes.Type mime = MimeTypes.CACHE.get(value); - String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString(); - if (charset != null) - _request.setCharacterEncodingUnchecked(charset); - break; - default: - } - } - - if (field.getName()!=null) - _request.getHttpFields().add(field); - } + _request.getHttpFields().addAll(request.getFields()); // TODO make this a better field for h2 hpack generation if (_configuration.getSendDateHeader()) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java new file mode 100644 index 00000000000..93b706744b2 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java @@ -0,0 +1,61 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server; + +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; + +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.MultiException; +import org.eclipse.jetty.util.MultiPartInputStreamParser; + +public class MultiPartCleanerListener implements ServletRequestListener +{ + @Override + public void requestDestroyed(ServletRequestEvent sre) + { + //Clean up any tmp files created by MultiPartInputStream + MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); + if (mpis != null) + { + ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); + + //Only do the cleanup if we are exiting from the context in which a servlet parsed the multipart files + if (context == sre.getServletContext()) + { + try + { + mpis.deleteParts(); + } + catch (MultiException e) + { + sre.getServletContext().log("Errors deleting multipart tmp files", e); + } + } + } + } + + @Override + public void requestInitialized(ServletRequestEvent sre) + { + //nothing to do, multipart config set up by ServletHolder.handle() + } + +} \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 9b09b8200a0..99cbfd4995e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -457,6 +457,8 @@ public class Request implements HttpServletRequest @Override public String getCharacterEncoding() { + if (_characterEncoding==null) + getContentType(); return _characterEncoding; } @@ -502,7 +504,15 @@ public class Request implements HttpServletRequest @Override public String getContentType() { - return _fields.getStringField(HttpHeader.CONTENT_TYPE); + String content_type = _fields.getStringField(HttpHeader.CONTENT_TYPE); + if (_characterEncoding==null && content_type!=null) + { + MimeTypes.Type mime = MimeTypes.CACHE.get(content_type); + String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(content_type) : mime.getCharset().toString(); + if (charset != null) + _characterEncoding=charset; + } + return content_type; } /* ------------------------------------------------------------ */ From 2b494fde0e7173214bf65455ecc940655450268f Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 17 Jun 2014 16:04:08 +0200 Subject: [PATCH 098/269] Miscellaneous refactorings. --- .../fcgi/server/HttpChannelOverFCGI.java | 37 ++++---- ...dMessage.java => BadMessageException.java} | 17 ++-- .../eclipse/jetty/http/HostPortHttpField.java | 19 ++-- .../org/eclipse/jetty/http/HttpParser.java | 63 +++++++------ .../java/org/eclipse/jetty/http/MetaData.java | 90 ++++--------------- .../http2/server/HttpChannelOverHTTP2.java | 2 +- .../org/eclipse/jetty/server/HttpChannel.java | 4 +- .../jetty/server/HttpChannelOverHttp.java | 7 +- .../spdy/server/http/HttpChannelOverSPDY.java | 43 ++++----- 9 files changed, 106 insertions(+), 176 deletions(-) rename jetty-http/src/main/java/org/eclipse/jetty/http/{BadMessage.java => BadMessageException.java} (81%) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java index e7e701d695a..9a71fd32d2c 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java @@ -18,10 +18,6 @@ package org.eclipse.jetty.fcgi.server; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; @@ -31,7 +27,6 @@ import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -54,7 +49,7 @@ public class HttpChannelOverFCGI extends HttpChannel private String path; private String query; private String version; - private HostPortHttpField host; + private HostPortHttpField hostPort; public HttpChannelOverFCGI(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) { @@ -72,13 +67,19 @@ public class HttpChannelOverFCGI extends HttpChannel query = field.getValue(); else if (FCGI.Headers.SERVER_PROTOCOL.equalsIgnoreCase(field.getName())) version = field.getValue(); - else if (field.getHeader()==HttpHeader.HOST) - { - host=new HostPortHttpField(HttpHeader.HOST,HttpHeader.HOST.asString(),field.getValue()); - fields.add(host); - } else - fields.add(field); + processField(field); + } + + private void processField(HttpField field) + { + HttpField httpField = convertHeader(field); + if (httpField != null) + { + fields.add(httpField); + if (HttpHeader.HOST.is(httpField.getName())) + hostPort = (HostPortHttpField)httpField; + } } public void onRequest() @@ -86,11 +87,7 @@ public class HttpChannelOverFCGI extends HttpChannel String uri = path; if (query != null && query.length() > 0) uri += "?" + query; - - if (host==null) - onRequest(new MetaData.Request(HttpVersion.fromString(version),method,new HttpURI(uri),fields,null,0)); - else - onRequest(new MetaData.Request(HttpVersion.fromString(version),method,new HttpURI(uri),fields,host.getHost(),host.getPort())); + onRequest(new MetaData.Request(HttpVersion.fromString(version), method, new HttpURI(uri), fields, hostPort)); } private HttpField convertHeader(HttpField field) @@ -109,7 +106,11 @@ public class HttpChannelOverFCGI extends HttpChannel httpName.append(Character.toUpperCase(part.charAt(0))); httpName.append(part.substring(1).toLowerCase(Locale.ENGLISH)); } - return new HttpField(httpName.toString(), field.getValue()); + String headerName = httpName.toString(); + if (HttpHeader.HOST.is(headerName)) + return new HostPortHttpField(field.getValue()); + else + return new HttpField(httpName.toString(), field.getValue()); } return null; } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java similarity index 81% rename from jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java rename to jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java index e92bd5e8ce4..014adc89d30 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessage.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java @@ -16,37 +16,36 @@ // ======================================================================== // - package org.eclipse.jetty.http; /* ------------------------------------------------------------------------------- */ -public class BadMessage extends Error +public class BadMessageException extends RuntimeException { final int _code; final String _reason; - public BadMessage() + public BadMessageException() { this(400,null); } - public BadMessage(int code) + public BadMessageException(int code) { this(code,null); } - public BadMessage(String reason) + public BadMessageException(String reason) { this(400,reason); } - public BadMessage(int code,String reason) + public BadMessageException(int code, String reason) { _code=code; _reason=reason; } - public BadMessage(int code,String reason,Throwable cause) + public BadMessageException(int code, String reason, Throwable cause) { super(cause); _code=code; @@ -62,6 +61,4 @@ public class BadMessage extends Error { return _reason; } - - -} \ No newline at end of file +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java index 4b8013ca726..683e82453e3 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java @@ -27,20 +27,15 @@ import org.eclipse.jetty.util.StringUtil; /** */ public class HostPortHttpField extends HttpField -{ - public final String _host; - public final int _port; +{ + private final String _host; + private final int _port; public HostPortHttpField(String authority) { this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority); } - public HostPortHttpField(HttpHeader header, String authority) - { - this(header,header.asString(),authority); - } - public HostPortHttpField(HttpHeader header, String name, String authority) { super(header,name,authority); @@ -52,13 +47,13 @@ public class HostPortHttpField extends HttpField // ipv6reference int close=authority.lastIndexOf(']'); if (close<0) - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad ipv6"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6"); _host=authority.substring(1,close); if (authority.length()>close+1) { if (authority.charAt(close+1)!=':') - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad ipv6 port"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6 port"); _port=StringUtil.toInt(authority,close+2); } else @@ -80,13 +75,13 @@ public class HostPortHttpField extends HttpField } } } - catch (BadMessage bm) + catch (BadMessageException bm) { throw bm; } catch(Exception e) { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad HostPort",e); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad HostPort",e); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 6478c54d08a..fc54f3235b6 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -25,7 +25,6 @@ import org.eclipse.jetty.http.HttpTokens.EndOfContent; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -339,7 +338,7 @@ public class HttpParser if (_cr) { if (ch!=HttpTokens.LINE_FEED) - throw new BadMessage("Bad EOL"); + throw new BadMessageException("Bad EOL"); _cr=false; return ch; } @@ -354,7 +353,7 @@ public class HttpParser _headerBytes++; ch=buffer.get(); if (ch!=HttpTokens.LINE_FEED) - throw new BadMessage("Bad EOL"); + throw new BadMessageException("Bad EOL"); } else { @@ -366,7 +365,7 @@ public class HttpParser } // Only LF or TAB acceptable special characters else if (!(ch==HttpTokens.LINE_FEED || ch==HttpTokens.TAB)) - throw new BadMessage("Illegal character"); + throw new BadMessageException("Illegal character"); } return ch; @@ -416,13 +415,13 @@ public class HttpParser else if (ch==0) break; else if (ch<0) - throw new BadMessage(); + throw new BadMessageException(); // count this white space as a header byte to avoid DOS if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) { LOG.warn("padding is too large >"+_maxHeaderBytes); - throw new BadMessage(HttpStatus.BAD_REQUEST_400); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400); } } return false; @@ -466,7 +465,7 @@ public class HttpParser if (_state==State.URI) { LOG.warn("URI is too large >"+_maxHeaderBytes); - throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414); + throw new BadMessageException(HttpStatus.REQUEST_URI_TOO_LONG_414); } else { @@ -474,7 +473,7 @@ public class HttpParser LOG.warn("request is too large >"+_maxHeaderBytes); else LOG.warn("response is too large >"+_maxHeaderBytes); - throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413); + throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413); } } @@ -491,7 +490,7 @@ public class HttpParser setState(State.SPACE1); } else if (ch < HttpTokens.SPACE) - throw new BadMessage(ch<0?"Illegal character":"No URI"); + throw new BadMessageException(ch<0?"Illegal character":"No URI"); else _string.append((char)ch); break; @@ -503,11 +502,11 @@ public class HttpParser String version=takeString(); _version=HttpVersion.CACHE.get(version); if (_version==null) - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version"); setState(State.SPACE1); } else if (ch < HttpTokens.SPACE) - throw new BadMessage(ch<0?"Illegal character":"No Status"); + throw new BadMessageException(ch<0?"Illegal character":"No Status"); else _string.append((char)ch); break; @@ -540,7 +539,7 @@ public class HttpParser if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) { LOG.warn("URI is too large >"+_maxHeaderBytes); - throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414); + throw new BadMessageException(HttpStatus.REQUEST_URI_TOO_LONG_414); } if (_uri.remaining()<=len) { @@ -558,7 +557,7 @@ public class HttpParser } else if (ch < HttpTokens.SPACE) { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status"); } break; @@ -578,7 +577,7 @@ public class HttpParser } else { - throw new BadMessage(); + throw new BadMessageException(); } break; @@ -591,7 +590,7 @@ public class HttpParser { // HTTP/0.9 _uri.flip(); - throw new BadMessage("HTTP/0.9 not supported"); + throw new BadMessageException("HTTP/0.9 not supported"); } else { @@ -631,7 +630,7 @@ public class HttpParser if (_method==HttpMethod.PROXY) { if (!(_requestHandler instanceof ProxyHandler)) - throw new BadMessage(); + throw new BadMessageException(); _uri.flip(); String protocol=BufferUtil.toString(_uri); @@ -682,11 +681,11 @@ public class HttpParser { // HTTP/0.9 _uri.flip(); - throw new BadMessage("HTTP/0.9 not supported"); + throw new BadMessageException("HTTP/0.9 not supported"); } } else if (ch<0) - throw new BadMessage(); + throw new BadMessageException(); break; case REQUEST_VERSION: @@ -698,7 +697,7 @@ public class HttpParser _version=HttpVersion.CACHE.get(takeString()); } if (_version==null) - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version"); // Should we try to cache header fields? if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion()) @@ -721,7 +720,7 @@ public class HttpParser else if (ch>=HttpTokens.SPACE) _string.append((char)ch); else - throw new BadMessage(); + throw new BadMessageException(); break; @@ -741,7 +740,7 @@ public class HttpParser _length=_string.length(); } else - throw new BadMessage(); + throw new BadMessageException(); break; default: @@ -774,7 +773,7 @@ public class HttpParser catch(NumberFormatException e) { LOG.ignore(e); - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Content-Length"); } if (_contentLength <= 0) _endOfContent=EndOfContent.NO_CONTENT; @@ -792,7 +791,7 @@ public class HttpParser _endOfContent=EndOfContent.CHUNKED_CONTENT; else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString())) { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad chunking"); } } break; @@ -865,7 +864,7 @@ public class HttpParser if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) { LOG.warn("Header is too large >"+_maxHeaderBytes); - throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413); + throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413); } switch (_state) @@ -876,7 +875,7 @@ public class HttpParser case HttpTokens.COLON: case HttpTokens.SPACE: case HttpTokens.TAB: - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Continuation"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Continuation"); case HttpTokens.LINE_FEED: { @@ -887,7 +886,7 @@ public class HttpParser // Was there a required host header? if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null) { - throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"No Host"); } // is it a response that cannot have a body? @@ -940,7 +939,7 @@ public class HttpParser { // now handle the ch if (ch<=HttpTokens.SPACE) - throw new BadMessage(); + throw new BadMessageException(); if (buffer.hasRemaining()) { @@ -1057,7 +1056,7 @@ public class HttpParser break; } - throw new BadMessage("Illegal character"); + throw new BadMessageException("Illegal character"); case HEADER_VALUE: if (ch>HttpTokens.SPACE || ch<0) @@ -1071,7 +1070,7 @@ public class HttpParser if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB) break; - throw new BadMessage(); + throw new BadMessageException(); case HEADER_IN_VALUE: if (ch>=HttpTokens.SPACE || ch<0 || ch==HttpTokens.TAB) @@ -1100,7 +1099,7 @@ public class HttpParser setState(State.HEADER); break; } - throw new BadMessage("Illegal character"); + throw new BadMessageException("Illegal character"); default: throw new IllegalStateException(_state.toString()); @@ -1228,7 +1227,7 @@ public class HttpParser return false; } - catch(BadMessage e) + catch(BadMessageException e) { BufferUtil.clear(buffer); @@ -1597,6 +1596,6 @@ public class HttpParser return _string.toString(); _string.append((char)ch); } - throw new BadMessage(); + throw new BadMessageException(); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index 5a28f74e38f..8740af384ce 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -16,16 +16,10 @@ // ======================================================================== // - package org.eclipse.jetty.http; import java.util.Iterator; -import java.util.List; - -/* ------------------------------------------------------------ */ -/** - */ public class MetaData implements Iterable { private final HttpVersion _version; @@ -63,73 +57,50 @@ public class MetaData implements Iterable return _fields; } - @Override - public boolean equals(Object o) - { - if (!(o instanceof MetaData)) - return false; - MetaData m = (MetaData)o; - - HttpFields lm=m.getFields(); - int s=0; - for (HttpField field: this) - { - s++; - if (!lm.contains(field)) - return false; - } - - if (s!=lm.size()) - return false; - - return true; - } - @Override public String toString() { StringBuilder out = new StringBuilder(); for (HttpField field: this) - out.append(field).append('\n'); + out.append(field).append(System.lineSeparator()); return out.toString(); } - /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ public static class Request extends MetaData { private final String _method; - private final HttpScheme _scheme; - private final String _host; - private final int _port; private final HttpURI _uri; + private final HostPortHttpField _hostPort; + private final HttpScheme _scheme; - public Request(HttpVersion version, String method, HttpURI uri, HttpFields fields,String host, int port) + public Request(HttpVersion version, String method, HttpURI uri, HttpFields fields, HostPortHttpField hostPort) { super(version,fields); - _host=host; - _port=port; _method=method; _uri=uri; - String scheme=uri.getScheme(); - if (scheme==null) - _scheme=HttpScheme.HTTP; + _hostPort = hostPort; + String scheme = uri.getScheme(); + if (scheme == null) + { + _scheme = HttpScheme.HTTP; + } else { HttpScheme s = HttpScheme.CACHE.get(scheme); - _scheme=s==null?HttpScheme.HTTP:s; + _scheme = s == null ? HttpScheme.HTTP : s; } } - + + // TODO: review this constructor: host/port parameters are ignored, and code duplication should be avoided. public Request(HttpVersion version, HttpScheme scheme, String method, String authority, String host, int port, String path, HttpFields fields) { super(version,fields); - _host=host; - _port=port; _method=method; _uri=new HttpURI(path); // TODO - this is not so efficient! + _hostPort = new HostPortHttpField(authority); _scheme=scheme; } @@ -157,12 +128,12 @@ public class MetaData implements Iterable public String getHost() { - return _host; + return _hostPort.getHost(); } public int getPort() { - return _port; + return _hostPort.getPort(); } public HttpURI getURI() @@ -170,25 +141,12 @@ public class MetaData implements Iterable return _uri; } - @Override - public boolean equals(Object o) - { - if (!(o instanceof Request)) - return false; - Request r = (Request)o; - if (!_method.equals(r._method) || - !_scheme.equals(r._scheme) || - !_uri.equals(r._uri)) - return false; - return super.equals(o); - } - @Override public String toString() { - return _method+" "+_scheme+"://"+_host+':'+_port+_uri+" HTTP/2\n"+super.toString(); + return String.format("%s %s://%s:%d%s HTTP/2%s%s", + getMethod(), getScheme(), getHost(), getPort(), getURI(), System.lineSeparator(), super.toString()); } - } /* -------------------------------------------------------- */ @@ -221,20 +179,10 @@ public class MetaData implements Iterable return _status; } - @Override - public boolean equals(Object o) - { - if (!(o instanceof Response)) - return false; - Response r = (Response)o; - if (_status!=r._status) - return false; - return super.equals(o); - } @Override public String toString() { - return "HTTP/2 "+_status+"\n"+super.toString(); + return String.format("HTTP/2 %d%s%s", getStatus(), System.lineSeparator(), super.toString()); } } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 65993f85c96..88ce6f714a9 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -66,7 +66,7 @@ public class HttpChannelOverHTTP2 extends HttpChannel // Based on that, some browser does not send the header, but it's // important that applications can find it (e.g. GzipFilter). HttpFields fields = request.getFields(); - if (!fields.contains(ACCEPT_ENCODING_GZIP)) + if (!fields.contains(HttpHeader.ACCEPT_ENCODING, "gzip")) fields.add(ACCEPT_ENCODING_GZIP); onRequest(request); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index d73d73ebc63..796a3e41a2e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -29,7 +29,7 @@ import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; -import org.eclipse.jetty.http.BadMessage; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; @@ -500,7 +500,7 @@ public class HttpChannel implements Runnable _request.setRequestURI(""); } else - throw new BadMessage(400,"Bad URI"); + throw new BadMessageException(400,"Bad URI"); } _request.setPathInfo(info); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 03737eed146..16e4d16e8c6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -295,10 +295,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl if (!persistent) _httpConnection._generator.setPersistent(false); - if (_hostPort==null) - onRequest(new MetaData.Request(_version,_method,_uri,_fields,null,0)); - else - onRequest(new MetaData.Request(_version,_method,_uri,_fields,_hostPort.getHost(),_hostPort.getPort())); + onRequest(new MetaData.Request(_version,_method,_uri,_fields,_hostPort)); return true; } @@ -332,4 +329,4 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl { return getHttpConfiguration().getHeaderCacheSize(); } -} \ No newline at end of file +} diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index a3042874547..cc8c0f5817d 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -20,10 +20,10 @@ package org.eclipse.jetty.spdy.server.http; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -106,15 +106,11 @@ public class HttpChannelOverSPDY extends HttpChannel LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion); - String scheme = "http"; Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version)); if (schemeHeader != null) - { - scheme = schemeHeader.getValue(); - getRequest().setScheme(scheme); - } + getRequest().setScheme(schemeHeader.getValue()); - String authority = null; + HostPortHttpField hostPort = null; HttpFields fields = new HttpFields(); for (Fields.Field header : headers) { @@ -128,7 +124,7 @@ public class HttpChannelOverSPDY extends HttpChannel continue; name = "host"; - authority = header.getValue(); + hostPort = new HostPortHttpField(header.getValue()); } switch (name) @@ -138,8 +134,13 @@ public class HttpChannelOverSPDY extends HttpChannel case "proxy-connection": case "transfer-encoding": { - // Spec says to ignore these headers - continue; + // Spec says to ignore these headers. + break; + } + case "host": + { + // Do not add it now. + break; } default: { @@ -152,24 +153,16 @@ public class HttpChannelOverSPDY extends HttpChannel } } - String host = null; - int port = 0; - if (authority != null) + if (hostPort == null) { - int colon = authority.indexOf(':'); - if (colon > 0) - { - host = authority.substring(0, colon); - port = Integer.valueOf(authority.substring(colon + 1)); - } - else - { - host = authority; - port = HttpScheme.HTTPS.is(scheme) ? 443 : 80; - } + onBadMessage(400, "Missing Host header"); + return false; } - MetaData.Request request = new MetaData.Request(httpVersion, httpMethod.asString(), uri, fields, host, port); + // At last, add the Host header. + fields.add(hostPort); + + MetaData.Request request = new MetaData.Request(httpVersion, httpMethod.asString(), uri, fields, hostPort); onRequest(request); return true; } From 82a2dfd03a6547ad6df8025db423a6025033c9ff Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 17 Jun 2014 18:51:09 +0200 Subject: [PATCH 099/269] Fixed infinite loop when receiving a SETTINGS frame. --- .../java/org/eclipse/jetty/http2/client/FlowControlTest.java | 2 +- .../src/main/java/org/eclipse/jetty/http2/HTTP2Session.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index 5d02bad399c..a46b750a4e1 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -103,7 +103,7 @@ public class FlowControlTest extends AbstractTest } }); - // Two SETTINGS frames, the initial one and the one we send. + // Two SETTINGS frames, the initial one and the one we send from the server. final CountDownLatch settingsLatch = new CountDownLatch(2); Session client = newClient(new Session.Listener.Adapter() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index ee949e45949..ae32afef6e4 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -163,6 +163,10 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { if (LOG.isDebugEnabled()) LOG.debug("Received {}", frame); + + if (frame.isReply()) + return false; + Map settings = frame.getSettings(); if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) { From 3832a8645d858de657a46859ca2ae841c8afb285 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 17 Jun 2014 18:52:42 +0200 Subject: [PATCH 100/269] Properly implemented hashCode() and equals(). --- .../org/eclipse/jetty/http/HttpField.java | 49 ++++++-------- .../org/eclipse/jetty/http/HttpFields.java | 41 +++++++++--- .../java/org/eclipse/jetty/http/MetaData.java | 66 ++++++++++++++++++- 3 files changed, 119 insertions(+), 37 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index d24fff8770c..f3b21d83892 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -20,9 +20,6 @@ package org.eclipse.jetty.http; import java.util.ArrayList; -import org.eclipse.jetty.util.QuotedStringTokenizer; - - /* ------------------------------------------------------------ */ /** A HTTP Field */ @@ -222,7 +219,27 @@ public class HttpField return false; } - @Override + private int nameHashCode() + { + int hash=13; + int len = _name.length(); + for (int i = 0; i < len; i++) + { + char c = Character.toUpperCase(_name.charAt(i)); + hash = 31 * hash + c; + } + return hash; + } + + @Override + public int hashCode() + { + if (_header==null) + return _value.hashCode() ^ nameHashCode(); + return _value.hashCode() ^ _header.hashCode(); + } + + @Override public boolean equals(Object o) { if (o==this) @@ -240,28 +257,4 @@ public class HttpField return false; return true; } - - public int nameHashCode() - { - int hash=13; - int len = _name.length(); - for (int i = 0; i < len; i++) - { - char c = Character.toUpperCase(_name.charAt(i)); - hash = 31 * hash + c; - } - return hash; - } - - @Override - public int hashCode() - { - if (_header==null) - return _value.hashCode() ^ nameHashCode(); - - return _value.hashCode() ^ _header.hashCode(); - } - - - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index c0a674bb630..f7d47d569d0 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -51,14 +51,12 @@ import org.eclipse.jetty.util.log.Logger; */ public class HttpFields implements Iterable { - private static final Logger LOG = Log.getLogger(HttpFields.class); - public final static String __separators = ", \t"; + public static final String __separators = ", \t"; - final List _fields; + private static final Logger LOG = Log.getLogger(HttpFields.class); + + private final List _fields; - /** - * Constructor. - */ public HttpFields() { _fields=new ArrayList<>(); @@ -563,8 +561,35 @@ public class HttpFields implements Iterable } @Override - public String - toString() + public int hashCode() + { + return _fields.hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof HttpFields)) + return false; + + HttpFields that = (HttpFields)o; + + // Order is not important, so we cannot rely on List.equals(). + if (size() != that.size()) + return false; + + for (HttpField field : this) + { + if (!that.contains(field)) + return false; + } + return true; + } + + @Override + public String toString() { try { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index 8740af384ce..39a975bfa6d 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -56,7 +56,28 @@ public class MetaData implements Iterable { return _fields; } - + + @Override + public int hashCode() + { + return 31 * _version.hashCode() + _fields.hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof MetaData)) + return false; + MetaData that = (MetaData)o; + + if (_version != that._version) + return false; + + return _fields.equals(that._fields); + } + @Override public String toString() { @@ -141,6 +162,30 @@ public class MetaData implements Iterable return _uri; } + @Override + public int hashCode() + { + int hash = _method.hashCode(); + hash = 31 * hash + _scheme.hashCode(); + hash = 31 * hash + _uri.hashCode(); + return 31 * hash + super.hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof Request)) + return false; + Request that = (Request)o; + if (!_method.equals(that._method) || + !_scheme.equals(that._scheme) || + !_uri.equals(that._uri)) + return false; + return super.equals(o); + } + @Override public String toString() { @@ -179,6 +224,25 @@ public class MetaData implements Iterable return _status; } + @Override + public int hashCode() + { + return 31 * _status + super.hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof Response)) + return false; + Response that = (Response)o; + if (_status != that._status) + return false; + return super.equals(o); + } + @Override public String toString() { From 3fcb910c1aa40929da0de5b9c0fc4f2e0349aaa8 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 17 Jun 2014 19:02:44 +0200 Subject: [PATCH 101/269] improved HttpField.contains --- .../org/eclipse/jetty/http/HttpField.java | 23 ++-- .../org/eclipse/jetty/http/HttpFields.java | 3 +- .../org/eclipse/jetty/http/HttpFieldTest.java | 106 ++++++++++++++++++ .../eclipse/jetty/http/HttpFieldsTest.java | 52 +++------ .../jetty/servlets/AsyncGzipFilter.java | 43 +++---- .../eclipse/jetty/servlets/GzipFilter.java | 2 + 6 files changed, 153 insertions(+), 76 deletions(-) create mode 100644 jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index f3b21d83892..75cd3e4fb16 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -86,8 +86,7 @@ public class HttpField state=2; break; - case ',': // leading empty field - list.add(""); + case ',': // ignore leading empty field break; case ' ': // more white space @@ -179,23 +178,27 @@ public class HttpField /* ------------------------------------------------------------ */ /** Look for a value in a possible multi valued field - * @param value + * @param search Values to search for * @return True iff the value is contained in the field value entirely or - * as an element of a quoted comma separated list + * as an element of a quoted comma separated list. List element parameters (eg qualities) are ignored. */ - public boolean contains(String value) + public boolean contains(String search) { - if (_value==null) - return value==null; + if (_value==null || search==null) + return _value==search; - if (_value.equalsIgnoreCase(value)) + if (_value.equals(search)) return true; String[] values = getValues(); for (String v:values) - if (v.equalsIgnoreCase(value)) + { + if (v.equals(search)) return true; - + if (v.startsWith(search) && v.charAt(search.length())==';') + return true; + } + return false; } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index f7d47d569d0..978593a9f02 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -140,7 +140,8 @@ public class HttpFields implements Iterable { for (int i=_fields.size();i-->0;) { - if (_fields.get(i).equals(field)) + HttpField f=_fields.get(i); + if (f.isSameName(field) && f.contains(field.getValue())) return true; } return false; diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java new file mode 100644 index 00000000000..bcdaaf96444 --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java @@ -0,0 +1,106 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.nio.ByteBuffer; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +import org.eclipse.jetty.util.BufferUtil; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +/** + * + */ +public class HttpFieldTest +{ + + @Test + public void testContainsSimple() throws Exception + { + HttpField field = new HttpField("name","somevalue"); + assertTrue(field.contains("somevalue")); + assertFalse(field.contains("other")); + assertFalse(field.contains("some")); + assertFalse(field.contains("value")); + assertFalse(field.contains("v")); + assertFalse(field.contains("")); + assertFalse(field.contains(null)); + } + + @Test + public void testContainsList() throws Exception + { + HttpField field = new HttpField("name",",aaa,bbb,ccc, ddd , e e, \"\\\"f,f\\\"\", "); + assertTrue(field.contains("aaa")); + assertTrue(field.contains("bbb")); + assertTrue(field.contains("ccc")); + assertTrue(field.contains("ddd")); + assertTrue(field.contains("e e")); + assertTrue(field.contains("\"f,f\"")); + assertFalse(field.contains("")); + assertFalse(field.contains("aa")); + assertFalse(field.contains("bb")); + assertFalse(field.contains("cc")); + assertFalse(field.contains(null)); + } + + + + + + @Test + public void testValues() + { + String[] values = new HttpField("name","value").getValues(); + assertEquals(1,values.length); + assertEquals("value",values[0]); + + + values = new HttpField("name","a,b,c").getValues(); + assertEquals(3,values.length); + assertEquals("a",values[0]); + assertEquals("b",values[1]); + assertEquals("c",values[2]); + + values = new HttpField("name","a,\"x,y,z\",c").getValues(); + assertEquals(3,values.length); + assertEquals("a",values[0]); + assertEquals("x,y,z",values[1]); + assertEquals("c",values[2]); + + values = new HttpField("name","a,\"x,\\\"p,q\\\",z\",c").getValues(); + assertEquals(3,values.length); + assertEquals("a",values[0]); + assertEquals("x,\"p,q\",z",values[1]); + assertEquals("c",values[2]); + + } +} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 3a65caa1218..139d03c1743 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -420,48 +420,22 @@ public class HttpFieldsTest { HttpFields header = new HttpFields(); - header.add("0", ""); - header.add("1", ","); - header.add("2", ",,"); - header.add("3", "abc"); - header.add("4", "def"); - header.add("5", "abc,def,hig"); - header.add("6", "abc"); - header.add("6", "def"); - header.add("6", "hig"); + header.add("n0", ""); + header.add("n1", ","); + header.add("n2", ",,"); + header.add("N3", "abc"); + header.add("N4", "def"); + header.add("n5", "abc,def,hig"); + header.add("N6", "abc"); + header.add("n6", "def"); + header.add("N6", "hig"); + header.add("n7", "abc , def;q=0.9 , hig"); - for (int i=0;i<7;i++) + for (int i=0;i<8;i++) { - assertFalse(""+i,header.contains(""+i,"xyz")); - assertEquals(""+i,i>=4,header.contains(""+i,"def")); + assertFalse(""+i,header.contains("n"+i,"xyz")); + assertEquals(""+i,i>=4,header.contains("n"+i,"def")); } } - @Test - public void testValues() - { - String[] values = new HttpField("name","value").getValues(); - assertEquals(1,values.length); - assertEquals("value",values[0]); - - - values = new HttpField("name","a,b,c").getValues(); - assertEquals(3,values.length); - assertEquals("a",values[0]); - assertEquals("b",values[1]); - assertEquals("c",values[2]); - - values = new HttpField("name","a,\"x,y,z\",c").getValues(); - assertEquals(3,values.length); - assertEquals("a",values[0]); - assertEquals("x,y,z",values[1]); - assertEquals("c",values[2]); - - values = new HttpField("name","a,\"x,\\\"p,q\\\",z\",c").getValues(); - assertEquals(3,values.length); - assertEquals("a",values[0]); - assertEquals("x,\"p,q\",z",values[1]); - assertEquals("c",values[2]); - - } } diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java index d4d773cfa8b..71e90a30e78 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java @@ -42,6 +42,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpOutput; @@ -126,7 +127,7 @@ import org.eclipse.jetty.util.log.Logger; */ public class AsyncGzipFilter extends UserAgentFilter implements GzipFactory { - private static final Logger LOG = Log.getLogger(GzipFilter.class); + private static final Logger LOG = Log.getLogger(AsyncGzipFilter.class); public final static String GZIP = "gzip"; public static final String DEFLATE = "deflate"; public final static String ETAG = "o.e.j.s.GzipFilter.ETag"; @@ -481,34 +482,24 @@ public class AsyncGzipFilter extends UserAgentFilter implements GzipFactory LOG.debug("{} excluded minGzipSize {}",this,request); return null; } - - String accept = request.getHttpFields().get(HttpHeader.ACCEPT_ENCODING); - if (accept==null) + + // If not HTTP/2, then we must check the accept encoding header + if (request.getHttpVersion().ordinal()!=HttpVersion.HTTP_2.ordinal()) { - LOG.debug("{} excluded !accept {}",this,request); - return null; - } - - boolean gzip=false; - if (GZIP.equals(accept) || accept.startsWith("gzip,")) - gzip=true; - else - { - List list=HttpFields.qualityList(request.getHttpFields().getValues(HttpHeader.ACCEPT_ENCODING.asString(),",")); - for (String a:list) + HttpField accept = request.getHttpFields().getField(HttpHeader.ACCEPT_ENCODING); + + if (accept==null) { - if (GZIP.equalsIgnoreCase(HttpFields.valueParameters(a,null))) - { - gzip=true; - break; - } + LOG.debug("{} excluded !accept {}",this,request); + return null; + } + boolean gzip = accept.contains("gzip"); + + if (!gzip) + { + LOG.debug("{} excluded not gzip accept {}",this,request); + return null; } - } - - if (!gzip) - { - LOG.debug("{} excluded not gzip accept {}",this,request); - return null; } Deflater df = _deflater.get(); diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java index 69f2f62f119..b324c95e547 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java @@ -121,7 +121,9 @@ import org.eclipse.jetty.util.log.Logger; * the normal processing is done so that the default servlet can send the pre existing gz content. * * + * @deprecated Use AsyncGzipFilter */ +@Deprecated public class GzipFilter extends UserAgentFilter { private static final Logger LOG = Log.getLogger(GzipFilter.class); From 7fa4f1e9f8e243e0e1e330e2f3cfb422445b33c0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 17 Jun 2014 19:40:09 +0200 Subject: [PATCH 102/269] cleaned up authority handling --- .../java/org/eclipse/jetty/http/MetaData.java | 9 +- .../frames/HeadersGenerateParseTest.java | 5 +- .../frames/PushPromiseGenerateParseTest.java | 5 +- .../jetty/http2/hpack/MetaDataBuilder.java | 13 +-- .../jetty/http2/server/HTTP2ServerTest.java | 7 +- .../org/eclipse/jetty/server/Request.java | 89 +++++-------------- 6 files changed, 39 insertions(+), 89 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index 39a975bfa6d..8267ee0db4e 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -115,13 +115,12 @@ public class MetaData implements Iterable } } - // TODO: review this constructor: host/port parameters are ignored, and code duplication should be avoided. - public Request(HttpVersion version, HttpScheme scheme, String method, String authority, String host, int port, String path, HttpFields fields) + public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, String path, HttpFields fields) { super(version,fields); _method=method; _uri=new HttpURI(path); // TODO - this is not so efficient! - _hostPort = new HostPortHttpField(authority); + _hostPort = authority; _scheme=scheme; } @@ -149,12 +148,12 @@ public class MetaData implements Iterable public String getHost() { - return _hostPort.getHost(); + return _hostPort==null?null:_hostPort.getHost(); } public int getPort() { - return _hostPort.getPort(); + return _hostPort==null?0:_hostPort.getPort(); } public HttpURI getURI() diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 0ff62a23d65..300a160c351 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; @@ -49,7 +50,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); final List frames = new ArrayList<>(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() @@ -115,7 +116,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateHeaders(lease, streamId, metaData, false); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index 60b14a73d1e..a190de4767a 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; @@ -61,7 +62,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) @@ -117,7 +118,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", "localhost:8080", "localhost", 8080, "/path", fields); + MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generatePushPromise(lease, streamId, promisedStreamId, metaData); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index fe7b63a6f43..710d562215d 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -35,9 +35,7 @@ public class MetaDataBuilder private int _status; private String _method; private HttpScheme _scheme; - private String _authority; - private String _host; - private int _port; + private HostPortHttpField _authority; private String _path; HttpFields _fields = new HttpFields(10); @@ -83,10 +81,7 @@ public class MetaDataBuilder break; case ":authority": - _authority=field.getValue(); - HostPortHttpField afield=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); - _host=afield.getHost(); - _port=afield.getPort(); + _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); break; case ":path": @@ -107,7 +102,7 @@ public class MetaDataBuilder HttpFields fields = _fields; _fields = new HttpFields(Math.max(10,fields.size()+5)); if (_method!=null) - return new MetaData.Request(HttpVersion.HTTP_2,_scheme,_method,_authority,_host,_port,_path,fields); + return new MetaData.Request(HttpVersion.HTTP_2,_scheme,_method,_authority,_path,fields); if (_status!=0) return new MetaData.Response(HttpVersion.HTTP_2,_status,fields); return new MetaData(HttpVersion.HTTP_2,fields); @@ -119,8 +114,6 @@ public class MetaDataBuilder _scheme=null; _authority=null; _path=null; - _host=null; - _port=0; } } } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 7405d9aac51..872a41db431 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -35,6 +35,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; @@ -106,7 +107,7 @@ public class HTTP2ServerTest int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), - host + ":" + port, host, port, path, fields); + new HostPortHttpField(host + ":" + port), path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, request); @@ -155,7 +156,7 @@ public class HTTP2ServerTest int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), - host + ":" + port, host, port, path, fields); + new HostPortHttpField(host + ":" + port), path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, request); @@ -218,7 +219,7 @@ public class HTTP2ServerTest int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2,HttpScheme.HTTP, HttpMethod.GET.asString(), - host + ":" + port, host, port, path, fields); + new HostPortHttpField(host + ":" + port), path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, request); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 99cbfd4995e..d4422168148 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -60,7 +60,9 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpUpgradeHandler; import javax.servlet.http.Part; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpCookie; +import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; @@ -149,7 +151,7 @@ public class Request implements HttpServletRequest private MultiMap _contentParameters; private MultiMap _parameters; private String _pathInfo; - private int _port; + private int _serverPort; private HttpVersion _httpVersion = HttpVersion.HTTP_1_1; private String _queryEncoding; private String _queryString; @@ -1174,57 +1176,19 @@ public class Request implements HttpServletRequest _serverName = _uri.getHost(); if (_serverName != null) { - _port = _uri.getPort(); + _serverPort = _uri.getPort(); return _serverName; } // Return host from header field - String hostPort = _fields.getStringField(HttpHeader.HOST); - - _port=0; - if (hostPort != null) + HttpField host = _fields.getField(HttpHeader.HOST); + if (host!=null) { - int len=hostPort.length(); - loop: for (int i = len; i-- > 0;) - { - char c2 = (char)(0xff & hostPort.charAt(i)); - switch (c2) - { - case ']': - break loop; - - case ':': - try - { - len=i; - _port = StringUtil.toInt(hostPort,i+1); - } - catch (NumberFormatException e) - { - LOG.warn(e); - _serverName=hostPort; - _port=0; - return _serverName; - } - break loop; - } - } - if (hostPort.charAt(0)=='[') - { - if (hostPort.charAt(len-1)!=']') - { - LOG.warn("Bad IPv6 "+hostPort); - _serverName=hostPort; - _port=0; - return _serverName; - } - _serverName = hostPort.substring(1,len-1); - } - else if (len==hostPort.length()) - _serverName=hostPort; - else - _serverName = hostPort.substring(0,len); - + HostPortHttpField authority = (host instanceof HostPortHttpField) + ?((HostPortHttpField)host) + :new HostPortHttpField(host.getValue()); + _serverName=authority.getHost(); + _serverPort=authority.getPort(); return _serverName; } @@ -1232,7 +1196,7 @@ public class Request implements HttpServletRequest if (_channel != null) { _serverName = getLocalName(); - _port = getLocalPort(); + _serverPort = getLocalPort(); if (_serverName != null && !StringUtil.ALL_INTERFACES.equals(_serverName)) return _serverName; } @@ -1256,30 +1220,21 @@ public class Request implements HttpServletRequest @Override public int getServerPort() { - if (_port <= 0) - { - if (_serverName == null) + // If we have no port and have not decoded a server name + if (_serverPort <= 0 && _serverName == null) + // decode a server name, which will set the port if it can getServerName(); - if (_port <= 0) - { - if (_serverName != null && _uri != null) - _port = _uri.getPort(); - else - { - InetSocketAddress local = _channel.getLocalAddress(); - _port = local == null?0:local.getPort(); - } - } - } - - if (_port <= 0) + // If no port specified, return the default port for the scheme + if (_serverPort <= 0) { if (getScheme().equalsIgnoreCase(URIUtil.HTTPS)) return 443; return 80; } - return _port; + + // return a specific port + return _serverPort; } /* ------------------------------------------------------------ */ @@ -1604,7 +1559,7 @@ public class Request implements HttpServletRequest _serverName = null; _httpMethod = null; _pathInfo = null; - _port = 0; + _serverPort = 0; _httpVersion = HttpVersion.HTTP_1_1; _queryEncoding = null; _queryString = null; @@ -1969,7 +1924,7 @@ public class Request implements HttpServletRequest */ public void setServerPort(int port) { - _port = port; + _serverPort = port; } /* ------------------------------------------------------------ */ From e115dee62f6b7f727cc6c49eacee4218085fcbc8 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 17 Jun 2014 19:54:21 +0200 Subject: [PATCH 103/269] improved static encoding strategy --- .../jetty/http2/hpack/HpackContext.java | 30 ++++++++++++------- .../jetty/http2/hpack/HpackEncoder.java | 5 ++-- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 9e1af505991..9bc92998143 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -120,29 +120,32 @@ public class HpackContext switch(i) { case 2: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.GET)); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.GET),true); break; case 3: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.POST)); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.POST),false); break; case 6: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTP)); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTP),true); break; case 7: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTPS)); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTPS),false); break; case 8: + case 11: + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1])),true); + break; + case 9: case 10: - case 11: case 12: case 13: case 14: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1]))); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1])),false); break; default: - entry=new StaticEntry(i,new HttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1])); + entry=new StaticEntry(i,new HttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1]),true); } __staticTable[i]=entry; @@ -160,8 +163,6 @@ public class HpackContext } } - public static final StaticEntry METHOD_GET=__staticTable[2]; - public static final StaticEntry STATUS_200=__staticTable[8]; private int _maxHeaderTableSizeInBytes; @@ -566,9 +567,10 @@ public class HpackContext public static class StaticEntry extends Entry { - final byte[] _huffmanValue; + private final byte[] _huffmanValue; + private final boolean _useRefSet; - StaticEntry(int index,HttpField field) + StaticEntry(int index,HttpField field,boolean useRefSet) { super(index,field); String value = field.getValue(); @@ -588,6 +590,7 @@ public class HpackContext } else _huffmanValue=null; + _useRefSet=useRefSet; } @Override @@ -596,6 +599,11 @@ public class HpackContext return true; } + public boolean useRefSet() + { + return _useRefSet; + } + @Override public byte[] getStaticHuffmanValue() { diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 47fb19324e7..457499757bc 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; +import org.eclipse.jetty.http2.hpack.HpackContext.StaticEntry; import org.eclipse.jetty.io.ByteBufferPool.Lease; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; @@ -204,9 +205,9 @@ public class HpackEncoder // TODO Strategy decision to make! // Should we add to reference set or just always send as indexed? - if (entry==HpackContext.METHOD_GET || entry==HpackContext.STATUS_200) + if (((StaticEntry)entry).useRefSet()) { - // :status: 200 and :method: GET are worthwhile putting into ref set. + // entries like :status: 200 and :method: GET are worthwhile putting into ref set. // as they are likely to be repeated. int index=_context.index(entry); buffer.put((byte)0x80); From 140e7ed0c56ea0afcabba1e1e142ad76d044220c Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 18 Jun 2014 10:22:23 +0200 Subject: [PATCH 104/269] encoder headers as lowercase --- .../jetty/http2/hpack/HpackContext.java | 4 +- .../jetty/http2/hpack/HpackDecoder.java | 9 ++++ .../jetty/http2/hpack/HpackEncoder.java | 8 ++-- .../eclipse/jetty/http2/hpack/Huffman.java | 43 +++++++++++++++---- .../jetty/http2/hpack/MetaDataBuilder.java | 2 +- .../eclipse/jetty/http2/hpack/HpackTest.java | 4 +- .../http2/server/HttpChannelOverHTTP2.java | 9 ++++ .../jetty/http2/server/Http2Server.java | 7 ++- .../test/resources/jetty-logging.properties | 2 + .../java/org/eclipse/jetty/util/Jetty.java | 2 +- 10 files changed, 70 insertions(+), 20 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 9bc92998143..21f16ec73e6 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -319,7 +319,7 @@ public class HpackContext else { if (LOG.isDebugEnabled()) - LOG.debug(String.format("RefSet[%x] remove unused",hashCode(),entry)); + LOG.debug(String.format("RefSet[%x] remove unused %s",hashCode(),entry)); // encode the reference to remove it buffer.put((byte)0x80); NBitInteger.encode(buffer,7,index(entry)); @@ -339,7 +339,7 @@ public class HpackContext else { if (LOG.isDebugEnabled()) - LOG.debug(String.format("RefSet[%x] emit unref",hashCode(),entry)); + LOG.debug(String.format("RefSet[%x] emit unref %s",hashCode(),entry)); builder.emit(entry.getHttpField()); } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index e74f80e8931..6771ff39833 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; @@ -132,6 +133,14 @@ public class HpackDecoder name=Huffman.decode(buffer,length); else name=toASCIIString(buffer,length); + for (int i=0;i='A'&&c<='Z') + { + throw new BadMessageException(400,"Uppercase header name"); + } + } header=HttpHeader.CACHE.get(name); } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 457499757bc..8f6574cfa43 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -302,10 +302,10 @@ public class HpackEncoder NBitInteger.encode(buffer,name_bits,_context.index(name_entry)); else { - // Encode the name always with huffman + // Encode the name always with lowercase huffman buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeeded(field.getName())); - Huffman.encode(buffer,field.getName()); + NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(field.getName())); + Huffman.encodeLC(buffer,field.getName()); } // Add the literal value @@ -339,8 +339,6 @@ public class HpackEncoder if (new_entry!=null) _context.addToRefSet(new_entry); } - - } if (p>=0) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java index 8889ff4bb7b..a80e193d9e3 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java @@ -287,15 +287,21 @@ public class Huffman }; + static final int[][] LCCODES = new int[CODES.length][]; + // Huffman decode tree stored in a flattened char array for good // locality of reference. static final char[] tree; static final char[] rowsym; static final byte[] rowbits; - // Build the Huffman lookup tree + // Build the Huffman lookup tree and LC TABLE static { + System.arraycopy(CODES,0,LCCODES,0,CODES.length); + for (int i='A';i<='Z';i++) + LCCODES[i]=LCCODES['a'+i-'A']; + int r=0; for (int i=0;i=128 || c<' ') throw new IllegalArgumentException(); - needed += CODES[c][1]; + needed += table[c][1]; } return (needed+7) / 8; } - static public void encode(ByteBuffer buffer,String s) + private static void encode(final int[][] table,ByteBuffer buffer,String s) { long current = 0; int n = 0; @@ -427,8 +453,8 @@ public class Huffman char c=s.charAt(i); if (c>=128 || c<' ') throw new IllegalArgumentException(); - int code = CODES[c][0]; - int bits = CODES[c][1]; + int code = table[c][0]; + int bits = table[c][1]; current <<= bits; current |= code; @@ -450,4 +476,5 @@ public class Huffman buffer.position(p-buffer.arrayOffset()); } + } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 710d562215d..a372667d0c6 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -41,7 +41,7 @@ public class MetaDataBuilder HttpFields _fields = new HttpFields(10); public void emit(HttpField field) - { + { if (field instanceof StaticValueHttpField) { StaticValueHttpField value = (StaticValueHttpField)field; diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index a088cec5abc..7cc665b4fd3 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -67,7 +67,7 @@ public class HpackTest fields1.add(HttpHeader.CONTENT_TYPE,"text/plain"); fields1.add(HttpHeader.CONTENT_LENGTH,"1234"); fields1.add(HttpHeader.SERVER,"jetty"); - fields1.add("custom-key","other-value"); + fields1.add("Custom-Key","Other-Value"); Response original1 = new Response(HttpVersion.HTTP_2,200,fields1); // Same again? @@ -77,7 +77,7 @@ public class HpackTest Response decoded1 = (Response)decoder.decode(buffer); Assert.assertEquals(original1,decoded1); - + Assert.assertEquals("custom-key",decoded1.getFields().getField("Custom-Key").getName()); } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 88ce6f714a9..270cc8d198d 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -43,6 +43,8 @@ public class HttpChannelOverHTTP2 extends HttpChannel { private static final Logger LOG = Log.getLogger(HttpChannelOverHTTP2.class); private static final HttpField ACCEPT_ENCODING_GZIP = new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip"); + private static final HttpField SERVER_VERSION=new HttpField(HttpHeader.SERVER,HttpConfiguration.SERVER_VERSION); + private static final HttpField POWERED_BY=new HttpField(HttpHeader.X_POWERED_BY,HttpConfiguration.SERVER_VERSION); private final Stream stream; public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input, Stream stream) @@ -69,6 +71,13 @@ public class HttpChannelOverHTTP2 extends HttpChannel if (!fields.contains(HttpHeader.ACCEPT_ENCODING, "gzip")) fields.add(ACCEPT_ENCODING_GZIP); + + // TODO make this a better field for h2 hpack generation + if (getHttpConfiguration().getSendServerVersion()) + getResponse().getHttpFields().add(SERVER_VERSION); + if (getHttpConfiguration().getSendXPoweredBy()) + getResponse().getHttpFields().add(POWERED_BY); + onRequest(request); if (frame.isEndStream()) diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java index 35eb759dc2d..64a19e85eca 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/Http2Server.java @@ -21,8 +21,10 @@ package org.eclipse.jetty.http2.server; import java.io.IOException; import java.util.Date; + import javax.servlet.Servlet; import javax.servlet.ServletException; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -116,7 +118,10 @@ public class Http2Server protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(true); - response.setHeader("custom","value"); + if (session.isNew()) + response.addCookie(new Cookie("bigcookie", + "This is a test cookies that was created on "+new Date()+" and is used by the jetty http/2 test servlet.")); + response.setHeader("Custom","Value"); response.setContentType("text/plain"); String content = "Hello from Jetty using "+request.getProtocol() +"\n"; content+="uri="+request.getRequestURI()+"\n"; diff --git a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties index b4e43807801..1a5ad20f950 100644 --- a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties @@ -1,2 +1,4 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog org.eclipse.jetty.http2.LEVEL=INFO +org.eclipse.jetty.http2.hpack.LEVEL=DEBUG + diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Jetty.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Jetty.java index 5a9b25705e1..dd1962fc9d7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Jetty.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Jetty.java @@ -30,7 +30,7 @@ public class Jetty pkg.getImplementationVersion() != null) VERSION = pkg.getImplementationVersion(); else - VERSION = System.getProperty("jetty.version", "9.2.z-SNAPSHOT"); + VERSION = System.getProperty("jetty.version", "9.3.z-SNAPSHOT"); } private Jetty() From 30affa57c7e2aed1f26902e13e7f476395aa253d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 18 Jun 2014 11:11:23 +0200 Subject: [PATCH 105/269] HpackDecoder implements 413 limit --- .../jetty/http2/hpack/HpackDecoder.java | 22 ++++++-- .../jetty/http2/hpack/MetaDataBuilder.java | 48 +++++++++++++++++- .../jetty/http2/hpack/HpackDecoderTest.java | 4 +- .../eclipse/jetty/http2/hpack/HpackTest.java | 50 ++++++++++++++++++- 4 files changed, 114 insertions(+), 10 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 6771ff39833..4a2ec08720c 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.TypeUtil; @@ -43,18 +44,21 @@ public class HpackDecoder public static final Logger LOG = Log.getLogger(HpackDecoder.class); private final HpackContext _context; - private final MetaDataBuilder _builder = new MetaDataBuilder(); + private final MetaDataBuilder _builder; private int _localMaxHeaderTableSize; + @Deprecated public HpackDecoder() { - this(4096); + this(4*1024,8*1024); + LOG.warn("USE HpackDecoder constructor with maxHeaderSize!!!"); } - public HpackDecoder(int localMaxHeaderTableSize) + public HpackDecoder(int localMaxHeaderTableSize, int maxHeaderSize) { _context=new HpackContext(localMaxHeaderTableSize); _localMaxHeaderTableSize=localMaxHeaderTableSize; + _builder = new MetaDataBuilder(maxHeaderSize); } public void setLocalMaxHeaderTableSize(int localMaxHeaderTableSize) @@ -63,9 +67,15 @@ public class HpackDecoder } public MetaData decode(ByteBuffer buffer) - { + { if (LOG.isDebugEnabled()) - LOG.debug(String.format("CtxTbl[%x] decoding",_context.hashCode())); + LOG.debug(String.format("CtxTbl[%x] decoding %d octets",_context.hashCode(),buffer.remaining())); + + // If the buffer is big, don't even think about decoding it + if (buffer.remaining()>_builder.getMaxSize()) + throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header frame size "+buffer.remaining()+">"+_builder.getMaxSize()); + + while(buffer.hasRemaining()) { if (LOG.isDebugEnabled()) @@ -129,6 +139,7 @@ public class HpackDecoder { huffmanName = (buffer.get()&0x80)==0x80; int length = NBitInteger.decode(buffer,7); + _builder.checkSize(length,huffmanName); if (huffmanName) name=Huffman.decode(buffer,length); else @@ -147,6 +158,7 @@ public class HpackDecoder // decode the value boolean huffmanValue = (buffer.get()&0x80)==0x80; int length = NBitInteger.decode(buffer,7); + _builder.checkSize(length,huffmanValue); if (huffmanValue) value=Huffman.decode(buffer,length); else diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index a372667d0c6..2ff9510b32a 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -20,10 +20,12 @@ package org.eclipse.jetty.http2.hpack; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -32,16 +34,44 @@ import org.eclipse.jetty.http.MetaData; /* -------------------------------------------------------- */ public class MetaDataBuilder { + private final int _maxSize; + private int _size; private int _status; private String _method; private HttpScheme _scheme; private HostPortHttpField _authority; private String _path; - HttpFields _fields = new HttpFields(10); + private HttpFields _fields = new HttpFields(10); + MetaDataBuilder(int maxSize) + { + _maxSize=maxSize; + } + + /** Get the maxSize. + * @return the maxSize + */ + public int getMaxSize() + { + return _maxSize; + } + + /** Get the size. + * @return the current size in bytes + */ + public int getSize() + { + return _size; + } + public void emit(HttpField field) { + int field_size = field.getName().length()+field.getValue().length(); + _size+=field_size; + if (_size>_maxSize) + throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+_size+">"+_maxSize); + if (field instanceof StaticValueHttpField) { StaticValueHttpField value = (StaticValueHttpField)field; @@ -65,7 +95,6 @@ public class MetaDataBuilder } else { - switch(field.getName()) { case ":status": @@ -114,6 +143,21 @@ public class MetaDataBuilder _scheme=null; _authority=null; _path=null; + _size=0; } } + + /* ------------------------------------------------------------ */ + /** Check that the max size will not be exceeded. + * @param length + * @param huffmanName + */ + public void checkSize(int length, boolean huffman) + { + // Apply a huffman fudge factor + if (huffman) + length=(length*4)/3; + if ((_size+length)>_maxSize) + throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+(_size+length)+">"+_maxSize); + } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index 7857a1bdbfd..9fcb6ac5e9e 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -43,7 +43,7 @@ public class HpackDecoderTest @Test public void testDecodeD_3() { - HpackDecoder decoder = new HpackDecoder(); + HpackDecoder decoder = new HpackDecoder(4096,8192); // First request String encoded="828786440f7777772e6578616d706c652e636f6d"; @@ -93,7 +93,7 @@ public class HpackDecoderTest @Test public void testDecodeD_4() { - HpackDecoder decoder = new HpackDecoder(); + HpackDecoder decoder = new HpackDecoder(4096,8192); // First request String encoded="828786448ce7cf9bebe89b6fb16fa9b6ff"; diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index 7cc665b4fd3..5a4b4a13f2e 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -19,11 +19,16 @@ package org.eclipse.jetty.http2.hpack; +import static org.junit.Assert.assertEquals; + import java.nio.ByteBuffer; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.junit.Assert; import org.junit.Test; import org.eclipse.jetty.http.MetaData.Request; @@ -37,7 +42,7 @@ public class HpackTest public void encodeDecodeResponseTest() { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(); + HpackDecoder decoder = new HpackDecoder(4096,8192); ByteBuffer buffer = BufferUtil.allocate(16*1024); HttpFields fields0 = new HttpFields(); @@ -80,4 +85,47 @@ public class HpackTest Assert.assertEquals("custom-key",decoded1.getFields().getField("Custom-Key").getName()); } + + + @Test + public void encodeDecodeTooLargeTest() + { + HpackEncoder encoder = new HpackEncoder(); + HpackDecoder decoder = new HpackDecoder(4096,101); + ByteBuffer buffer = BufferUtil.allocate(16*1024); + + HttpFields fields0 = new HttpFields(); + fields0.add("1234567890","1234567890123456789012345678901234567890"); + fields0.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); + MetaData original0= new MetaData(HttpVersion.HTTP_2,fields0); + + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,original0); + BufferUtil.flipToFlush(buffer,0); + MetaData decoded0 = (MetaData)decoder.decode(buffer); + + Assert.assertEquals(original0,decoded0); + + HttpFields fields1 = new HttpFields(); + fields1.add("1234567890","1234567890123456789012345678901234567890"); + fields1.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); + fields1.add("x","y"); + MetaData original1 = new MetaData(HttpVersion.HTTP_2,fields1); + + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,original1); + BufferUtil.flipToFlush(buffer,0); + try + { + decoder.decode(buffer); + Assert.fail(); + } + catch(BadMessageException e) + { + assertEquals(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,e.getCode()); + } + + } + + } From aef2f42b5b7d542e843d6a739e48fbdc2722f77b Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 17 Jun 2014 22:12:49 +0200 Subject: [PATCH 106/269] FastCGI applications needs the Host header, which is missing in HTTP/2. --- .../java/org/eclipse/jetty/client/HttpClient.java | 2 +- .../jetty/fcgi/server/proxy/FastCGIProxyServlet.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index 3486c811039..e636985b717 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -946,7 +946,7 @@ public class HttpClient extends ContainerLifeCycle return port > 0 ? port : HttpScheme.HTTPS.is(scheme) ? 443 : 80; } - protected boolean isDefaultPort(String scheme, int port) + public boolean isDefaultPort(String scheme, int port) { return HttpScheme.HTTPS.is(scheme) ? port == 443 : port == 80; } diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java index d107011752d..15c7d425520 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java @@ -31,6 +31,7 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.fcgi.client.http.HttpClientTransportOverFCGI; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.proxy.AsyncProxyServlet; import org.eclipse.jetty.proxy.ProxyServlet; @@ -127,6 +128,16 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent proxyRequest.attribute(REQUEST_URI_ATTRIBUTE, originalURI); } + // If the Host header is missing, add it. + if (!proxyRequest.getHeaders().containsKey(HttpHeader.HOST.asString())) + { + String host = request.getServerName(); + int port = request.getServerPort(); + if (!getHttpClient().isDefaultPort(request.getScheme(), port)) + host += ":" + port; + proxyRequest.header(HttpHeader.HOST, host); + } + super.customizeProxyRequest(proxyRequest, request); } From c0e0b802d936b853a4b056cbd861bdf742035d7a Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 18 Jun 2014 10:26:57 +0200 Subject: [PATCH 107/269] Made sure that exceptions thrown by the parser are caught and the connection closed. --- .../eclipse/jetty/http2/parser/Parser.java | 123 ++++++++++-------- .../jetty/http2/parser/ServerParser.java | 51 +++++--- 2 files changed, 96 insertions(+), 78 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index dbccae1f61e..d640d82bf6e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -74,79 +74,88 @@ public class Parser public boolean parse(ByteBuffer buffer) { - if (LOG.isDebugEnabled()) - LOG.debug("Parsing {}", buffer); - - while (true) + try { - switch (state) + if (LOG.isDebugEnabled()) + LOG.debug("Parsing {}", buffer); + + while (true) { - case HEADER: + switch (state) { - if (!headerParser.parse(buffer)) - return false; - state = State.BODY; - break; - } - case BODY: - { - int type = headerParser.getFrameType(); - if (LOG.isDebugEnabled()) - LOG.debug("Parsing {} frame", FrameType.from(type)); - if (type < 0 || type >= bodyParsers.length) + case HEADER: { - notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "unknown_frame_type_" + type); - return false; - } - BodyParser bodyParser = bodyParsers[type]; - if (headerParser.getLength() == 0) - { - boolean async = bodyParser.emptyBody(); - reset(); - if (async) - return true; - if (!buffer.hasRemaining()) + if (!headerParser.parse(buffer)) return false; + state = State.BODY; + break; } - else + case BODY: { - BodyParser.Result result = bodyParser.parse(buffer); - switch (result) + int type = headerParser.getFrameType(); + if (LOG.isDebugEnabled()) + LOG.debug("Parsing {} frame", FrameType.from(type)); + if (type < 0 || type >= bodyParsers.length) { - case PENDING: - { - // Not enough bytes. - return false; - } - case ASYNC: - { - // The content will be processed asynchronously, stop parsing; - // the asynchronous operation will eventually resume parsing. - if (LOG.isDebugEnabled()) - LOG.debug("Parsed {} frame, asynchronous processing", FrameType.from(type)); + notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "unknown_frame_type_" + type); + return false; + } + BodyParser bodyParser = bodyParsers[type]; + if (headerParser.getLength() == 0) + { + boolean async = bodyParser.emptyBody(); + reset(); + if (async) return true; - } - case COMPLETE: + if (!buffer.hasRemaining()) + return false; + } + else + { + BodyParser.Result result = bodyParser.parse(buffer); + switch (result) { - if (LOG.isDebugEnabled()) - LOG.debug("Parsed {} frame, synchronous processing", FrameType.from(type)); - reset(); - break; - } - default: - { - throw new IllegalStateException(); + case PENDING: + { + // Not enough bytes. + return false; + } + case ASYNC: + { + // The content will be processed asynchronously, stop parsing; + // the asynchronous operation will eventually resume parsing. + if (LOG.isDebugEnabled()) + LOG.debug("Parsed {} frame, asynchronous processing", FrameType.from(type)); + return true; + } + case COMPLETE: + { + if (LOG.isDebugEnabled()) + LOG.debug("Parsed {} frame, synchronous processing", FrameType.from(type)); + reset(); + break; + } + default: + { + throw new IllegalStateException(); + } } } + break; + } + default: + { + throw new IllegalStateException(); } - break; - } - default: - { - throw new IllegalStateException(); } } } + catch (Throwable x) + { + LOG.debug(x); + notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "parser_error"); + return false; + } } protected void notifyConnectionFailure(int error, String reason) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java index 80ea9610acc..6d81c2e92fc 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java @@ -42,33 +42,42 @@ public class ServerParser extends Parser @Override public boolean parse(ByteBuffer buffer) { - if (LOG.isDebugEnabled()) - LOG.debug("Parsing {}", buffer); - - while (true) + try { - switch (state) + if (LOG.isDebugEnabled()) + LOG.debug("Parsing {}", buffer); + + while (true) { - case PREFACE: + switch (state) { - if (!prefaceParser.parse(buffer)) - return false; - if (onPreface()) - return true; - state = State.FRAMES; - break; - } - case FRAMES: - { - // Stay forever in the FRAMES state. - return super.parse(buffer); - } - default: - { - throw new IllegalStateException(); + case PREFACE: + { + if (!prefaceParser.parse(buffer)) + return false; + if (onPreface()) + return true; + state = State.FRAMES; + break; + } + case FRAMES: + { + // Stay forever in the FRAMES state. + return super.parse(buffer); + } + default: + { + throw new IllegalStateException(); + } } } } + catch (Throwable x) + { + LOG.debug(x); + notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "parser_error"); + return false; + } } protected boolean onPreface() From 690cd0193390c2e0919bcb204ecddd956ea00800 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 18 Jun 2014 10:31:07 +0200 Subject: [PATCH 108/269] Made sure that exceptions thrown by the generator are caught and the connection closed. --- .../src/main/java/org/eclipse/jetty/http2/HTTP2Session.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index ae32afef6e4..14eeef4e3c5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -741,6 +741,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void failed(Throwable x) { + close(ErrorCode.INTERNAL_ERROR, "generator_error", Adapter.INSTANCE); callback.failed(x); } @@ -791,7 +792,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener stream.updateClose(dataFrame.isEndStream(), true); if (stream.isClosed()) removeStream(stream, true); - callback.succeeded(); + super.succeeded(); } } } From 9c95e29088d756d3e9feef8813bbcd2a89858f40 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 18 Jun 2014 11:18:15 +0200 Subject: [PATCH 109/269] Implemented idle timeout functionality for both client and server. --- .../jetty/http2/client/HTTP2Client.java | 22 +- .../jetty/http2/client/AbstractTest.java | 7 +- .../jetty/http2/client/FlowControlTest.java | 18 +- .../eclipse/jetty/http2/client/HTTP2Test.java | 8 +- .../jetty/http2/client/IdleTimeoutTest.java | 253 ++++++++++++++++++ .../eclipse/jetty/http2/client/PingTest.java | 4 +- .../eclipse/jetty/http2/HTTP2Connection.java | 9 + .../org/eclipse/jetty/http2/HTTP2Session.java | 30 ++- .../AbstractHTTP2ServerConnectionFactory.java | 10 + 9 files changed, 337 insertions(+), 24 deletions(-) create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index 1da1295256a..5bf7ceb41c6 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -53,6 +53,7 @@ public class HTTP2Client extends ContainerLifeCycle private final Queue sessions = new ConcurrentLinkedQueue<>(); private final SelectorManager selector; private final ByteBufferPool byteBufferPool; + private long idleTimeout; public HTTP2Client() { @@ -100,6 +101,16 @@ public class HTTP2Client extends ContainerLifeCycle sessions.clear(); } + public long getIdleTimeout() + { + return idleTimeout; + } + + public void setIdleTimeout(long idleTimeout) + { + this.idleTimeout = idleTimeout; + } + private class ClientSelectorManager extends SelectorManager { private ClientSelectorManager(Executor executor, Scheduler scheduler) @@ -110,7 +121,7 @@ public class HTTP2Client extends ContainerLifeCycle @Override protected EndPoint newEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException { - return new SelectChannelEndPoint(channel, selector, selectionKey, getScheduler(), 30000); + return new SelectChannelEndPoint(channel, selector, selectionKey, getScheduler(), getIdleTimeout()); } @Override @@ -150,6 +161,15 @@ public class HTTP2Client extends ContainerLifeCycle sessions.remove(session); } + @Override + protected boolean onReadTimeout() + { + if (LOG.isDebugEnabled()) + LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); + session.close(ErrorCode.NO_ERROR, "idle_timeout", closeCallback); + return false; + } + @Override public void succeeded() { diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java index ac48a66db52..1f0cff2e03b 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -22,6 +22,7 @@ import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServlet; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpVersion; @@ -42,9 +43,9 @@ import org.junit.After; public class AbstractTest { - private ServerConnector connector; + protected ServerConnector connector; private String path = "/test"; - private HTTP2Client client; + protected HTTP2Client client; private Server server; protected void startServer(HttpServlet servlet) throws Exception @@ -106,6 +107,6 @@ public class AbstractTest String host = "localhost"; int port = connector.getLocalPort(); String authority = host + ":" + port; - return new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, method, authority, host, port, path, fields); + return new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, method, new HostPortHttpField(authority), path, fields); } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index a46b750a4e1..def59646e98 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -105,7 +105,7 @@ public class FlowControlTest extends AbstractTest // Two SETTINGS frames, the initial one and the one we send from the server. final CountDownLatch settingsLatch = new CountDownLatch(2); - Session client = newClient(new Session.Listener.Adapter() + Session session = newClient(new Session.Listener.Adapter() { @Override public void onSettings(Session session, SettingsFrame frame) @@ -116,7 +116,7 @@ public class FlowControlTest extends AbstractTest MetaData.Request request = newRequest("POST", new HttpFields()); FuturePromise promise = new FuturePromise<>(); - client.newStream(new HeadersFrame(0, request, null, false), promise, new Stream.Listener.Adapter()); + session.newStream(new HeadersFrame(0, request, null, false), promise, new Stream.Listener.Adapter()); Stream stream = promise.get(5, TimeUnit.SECONDS); // Send first chunk that exceeds the window. @@ -356,11 +356,11 @@ public class FlowControlTest extends AbstractTest } }); - Session client = newClient(new Session.Listener.Adapter()); + Session session = newClient(new Session.Listener.Adapter()); Map settings = new HashMap<>(); settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize); - client.settings(new SettingsFrame(settings, false), Callback.Adapter.INSTANCE); + session.settings(new SettingsFrame(settings, false), Callback.Adapter.INSTANCE); Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); @@ -369,7 +369,7 @@ public class FlowControlTest extends AbstractTest // First request will consume half the session window. MetaData.Request request1 = newRequest("GET", new HttpFields()); - client.newStream(new HeadersFrame(0, request1, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() + session.newStream(new HeadersFrame(0, request1, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() { @Override public void onData(Stream stream, DataFrame frame, Callback callback) @@ -382,7 +382,7 @@ public class FlowControlTest extends AbstractTest // Second request will consume the session window, which is now stalled. // A third request will not be able to receive data. MetaData.Request request2 = newRequest("GET", new HttpFields()); - client.newStream(new HeadersFrame(0, request2, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() + session.newStream(new HeadersFrame(0, request2, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() { @Override public void onData(Stream stream, DataFrame frame, Callback callback) @@ -395,7 +395,7 @@ public class FlowControlTest extends AbstractTest // Third request is now stalled. final CountDownLatch latch = new CountDownLatch(1); MetaData.Request request3 = newRequest("GET", new HttpFields()); - client.newStream(new HeadersFrame(0, request3, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() + session.newStream(new HeadersFrame(0, request3, null, true), new Promise.Adapter(), new Stream.Listener.Adapter() { @Override public void onData(Stream stream, DataFrame frame, Callback callback) @@ -438,12 +438,12 @@ public class FlowControlTest extends AbstractTest } }); - Session client = newClient(new Session.Listener.Adapter()); + Session session = newClient(new Session.Listener.Adapter()); MetaData.Request metaData = newRequest("GET", new HttpFields()); HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); final byte[] bytes = new byte[data.length]; final CountDownLatch latch = new CountDownLatch(1); - client.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter() + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter() { private int received; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index e68bbf00c02..6a6468bc959 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -46,13 +46,13 @@ public class HTTP2Test extends AbstractTest { startServer(new EmptyHttpServlet()); - Session client = newClient(new Session.Listener.Adapter()); + Session session = newClient(new Session.Listener.Adapter()); HttpFields fields = new HttpFields(); MetaData.Request metaData = newRequest("GET", fields); HeadersFrame frame = new HeadersFrame(1, metaData, null, true); final CountDownLatch latch = new CountDownLatch(1); - client.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() + session.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() { @Override public void onHeaders(Stream stream, HeadersFrame frame) @@ -86,13 +86,13 @@ public class HTTP2Test extends AbstractTest } }); - Session client = newClient(new Session.Listener.Adapter()); + Session session = newClient(new Session.Listener.Adapter()); HttpFields fields = new HttpFields(); MetaData.Request metaData = newRequest("GET", fields); HeadersFrame frame = new HeadersFrame(1, metaData, null, true); final CountDownLatch latch = new CountDownLatch(2); - client.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() + session.newStream(frame, new Promise.Adapter(), new Stream.Listener.Adapter() { @Override public void onHeaders(Stream stream, HeadersFrame frame) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java new file mode 100644 index 00000000000..b392af4e766 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java @@ -0,0 +1,253 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http2.client; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.GoAwayFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; +import org.junit.Assert; +import org.junit.Test; + +public class IdleTimeoutTest extends AbstractTest +{ + private final int idleTimeout = 1000; + + @Test + public void testServerEnforcingIdleTimeout() throws Exception + { + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) + { + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + return null; + } + }); + connector.setIdleTimeout(idleTimeout); + + final CountDownLatch latch = new CountDownLatch(1); + Session session = newClient(new Session.Listener.Adapter() + { + @Override + public void onClose(Session session, GoAwayFrame frame) + { + latch.countDown(); + } + }); + + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + + Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + } + + @Test + public void testServerEnforcingIdleTimeoutWithUnrespondedStream() throws Exception + { + startServer(new ServerSessionListener.Adapter()); + connector.setIdleTimeout(idleTimeout); + + final CountDownLatch latch = new CountDownLatch(1); + Session session = newClient(new Session.Listener.Adapter() + { + @Override + public void onClose(Session session, GoAwayFrame frame) + { + latch.countDown(); + } + }); + + // The request is not replied, and the server should idle timeout. + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + + Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + } + + @Test + public void testServerNotEnforcingIdleTimeoutWithPendingStream() throws Exception + { + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + try + { + Thread.sleep(2 * idleTimeout); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + return null; + } + catch (InterruptedException x) + { + Assert.fail(); + return null; + } + } + }); + connector.setIdleTimeout(idleTimeout); + + final CountDownLatch closeLatch = new CountDownLatch(1); + Session session = newClient(new ServerSessionListener.Adapter() + { + @Override + public void onClose(Session session, GoAwayFrame frame) + { + closeLatch.countDown(); + } + }); + + final CountDownLatch replyLatch = new CountDownLatch(1); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + replyLatch.countDown(); + } + }); + + Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS)); + + // Just make sure onClose() has never been called, but don't wait too much + Assert.assertFalse(closeLatch.await(idleTimeout / 2, TimeUnit.MILLISECONDS)); + } + + @Test + public void testClientEnforcingIdleTimeout() throws Exception + { + final CountDownLatch closeLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + return null; + } + + @Override + public void onClose(Session session, GoAwayFrame frame) + { + closeLatch.countDown(); + } + }); + client.setIdleTimeout(idleTimeout); + + Session session = newClient(new Session.Listener.Adapter()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + + Assert.assertTrue(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + } + + @Test + public void testClientEnforcingIdleTimeoutWithUnrespondedStream() throws Exception + { + final CountDownLatch closeLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public void onClose(Session session, GoAwayFrame frame) + { + closeLatch.countDown(); + } + }); + client.setIdleTimeout(idleTimeout); + + Session session = newClient(new Session.Listener.Adapter()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + + Assert.assertTrue(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + } + + @Test + public void testClientNotEnforcingIdleTimeoutWithPendingStream() throws Exception + { + final CountDownLatch closeLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + return null; + } + + @Override + public void onClose(Session session, GoAwayFrame frame) + { + closeLatch.countDown(); + } + }); + client.setIdleTimeout(idleTimeout); + + Session session = newClient(new Session.Listener.Adapter()); + + final CountDownLatch replyLatch = new CountDownLatch(1); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + try + { + Thread.sleep(2 * idleTimeout); + replyLatch.countDown(); + } + catch (InterruptedException e) + { + Assert.fail(); + } + } + }); + + Assert.assertFalse(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS)); + } +} diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java index 0d612b639fc..0843c4b9222 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java @@ -39,7 +39,7 @@ public class PingTest extends AbstractTest final byte[] payload = new byte[8]; new Random().nextBytes(payload); final CountDownLatch latch = new CountDownLatch(1); - Session client = newClient(new Session.Listener.Adapter() + Session session = newClient(new Session.Listener.Adapter() { @Override public void onPing(Session session, PingFrame frame) @@ -51,7 +51,7 @@ public class PingTest extends AbstractTest }); PingFrame frame = new PingFrame(payload, false); - client.ping(frame, Callback.Adapter.INSTANCE); + session.ping(frame, Callback.Adapter.INSTANCE); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index a86e7e8b107..cd545dc194a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -33,6 +34,14 @@ public class HTTP2Connection extends AbstractConnection { protected static final Logger LOG = Log.getLogger(HTTP2Connection.class); + protected final Callback closeCallback = new Callback.Adapter() + { + @Override + public void failed(Throwable x) + { + close(); + } + }; private final ByteBufferPool byteBufferPool; private final Parser parser; private final int bufferSize; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 14eeef4e3c5..f6013ca2dff 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.http2.api.Session; @@ -77,6 +78,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final AtomicInteger lastStreamId = new AtomicInteger(); private final AtomicInteger streamCount = new AtomicInteger(); private final AtomicInteger windowSize = new AtomicInteger(); + private final AtomicBoolean closed = new AtomicBoolean(); private final EndPoint endPoint; private final Generator generator; private final Listener listener; @@ -223,6 +225,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.close(); disconnect(); + + notifyClose(this, frame); + return false; } @@ -315,11 +320,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void close(int error, String reason, Callback callback) { - byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); - GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); - if (LOG.isDebugEnabled()) - LOG.debug("Sending {}: {}", frame.getType(), reason); - control(null, frame, callback); + if (closed.compareAndSet(false, true)) + { + byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); + GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); + if (LOG.isDebugEnabled()) + LOG.debug("Sending {}: {}", frame.getType(), reason); + control(null, frame, callback); + } } @Override @@ -490,6 +498,18 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } + protected void notifyClose(Session session, GoAwayFrame frame) + { + try + { + listener.onClose(session, frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } + @Override public String toString() { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 77ae91d6264..67c485e60bd 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -25,6 +25,7 @@ import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.ByteBufferPool; @@ -111,6 +112,15 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne notifyConnect(session); } + @Override + protected boolean onReadTimeout() + { + if (LOG.isDebugEnabled()) + LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); + session.close(ErrorCode.NO_ERROR, "idle_timeout", closeCallback); + return false; + } + private void notifyConnect(Session session) { try From 4dca6a71d3253dc052f8cd47cdf3cb6957ef8276 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 18 Jun 2014 11:40:11 +0200 Subject: [PATCH 110/269] Update Parser constructor to take additional parameters needed by HpackDecoder. --- .../eclipse/jetty/http2/client/HTTP2Client.java | 2 +- .../org/eclipse/jetty/http2/parser/Parser.java | 4 ++-- .../eclipse/jetty/http2/parser/ServerParser.java | 4 ++-- .../http2/frames/DataGenerateParseTest.java | 4 ++-- .../http2/frames/GoAwayGenerateParseTest.java | 4 ++-- .../http2/frames/HeadersGenerateParseTest.java | 4 ++-- .../http2/frames/PingGenerateParseTest.java | 4 ++-- .../http2/frames/PriorityGenerateParseTest.java | 4 ++-- .../frames/PushPromiseGenerateParseTest.java | 4 ++-- .../http2/frames/ResetGenerateParseTest.java | 4 ++-- .../http2/frames/SettingsGenerateParseTest.java | 6 +++--- .../frames/WindowUpdateGenerateParseTest.java | 4 ++-- .../eclipse/jetty/http2/hpack/HpackDecoder.java | 8 -------- .../AbstractHTTP2ServerConnectionFactory.java | 16 +++++++++------- .../server/HTTP2ServerConnectionFactory.java | 10 +++++++++- .../server/RawHTTP2ServerConnectionFactory.java | 9 +++++++++ .../jetty/http2/server/HTTP2ServerTest.java | 11 +++++------ 17 files changed, 56 insertions(+), 46 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index 5bf7ceb41c6..c9c0735085a 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -130,7 +130,7 @@ public class HTTP2Client extends ContainerLifeCycle Context context = (Context)attachment; Generator generator = new Generator(byteBufferPool, 4096); HTTP2Session session = new HTTP2ClientSession(endpoint, generator, context.listener, new HTTP2FlowControl(65535)); - Parser parser = new Parser(byteBufferPool, session); + Parser parser = new Parser(byteBufferPool, session, 4096, 8192); return new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, 8192, context.promise, session); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index d640d82bf6e..b0d8751ad86 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -44,13 +44,13 @@ public class Parser private final BodyParser[] bodyParsers; private State state = State.HEADER; - public Parser(ByteBufferPool byteBufferPool, Listener listener) + public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxHeaderTableSize, int maxHeaderSize) { this.listener = listener; this.headerParser = new HeaderParser(); this.bodyParsers = new BodyParser[FrameType.values().length]; - HeaderBlockParser headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder()); + HeaderBlockParser headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder(maxHeaderTableSize, maxHeaderSize)); bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener); bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java index 6d81c2e92fc..5e5754e41b2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java @@ -32,9 +32,9 @@ public class ServerParser extends Parser private final PrefaceParser prefaceParser; private State state = State.PREFACE; - public ServerParser(ByteBufferPool byteBufferPool, Listener listener) + public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxHeaderTableSize, int maxHeaderSize) { - super(byteBufferPool, listener); + super(byteBufferPool, listener, maxHeaderTableSize, maxHeaderSize); this.listener = listener; this.prefaceParser = new PrefaceParser(listener); } diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 8a635177c32..cbcf0b62c2c 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -98,7 +98,7 @@ public class DataGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) @@ -130,7 +130,7 @@ public class DataGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); ByteBuffer data = ByteBuffer.wrap(largeContent); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java index dfe80d727f4..f64deae38f1 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java @@ -49,7 +49,7 @@ public class GoAwayGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int lastStreamId = 13; int error = 17; @@ -91,7 +91,7 @@ public class GoAwayGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int lastStreamId = 13; int error = 17; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 300a160c351..810145a6a05 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -61,7 +61,7 @@ public class HeadersGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) @@ -110,7 +110,7 @@ public class HeadersGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; HttpFields fields = new HttpFields(); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java index b61a12fc5c5..7327579392c 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -49,7 +49,7 @@ public class PingGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); byte[] payload = new byte[8]; new Random().nextBytes(payload); @@ -90,7 +90,7 @@ public class PingGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); byte[] payload = new byte[8]; new Random().nextBytes(payload); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index 9a107a3edce..12053440aca 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -48,7 +48,7 @@ public class PriorityGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; int dependentStreamId = 17; @@ -93,7 +93,7 @@ public class PriorityGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; int dependentStreamId = 17; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index a190de4767a..8826cbbcde5 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -55,7 +55,7 @@ public class PushPromiseGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; int promisedStreamId = 17; @@ -111,7 +111,7 @@ public class PushPromiseGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; int promisedStreamId = 17; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index 503992ddcda..b202c37df17 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -48,7 +48,7 @@ public class ResetGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; int error = 17; @@ -89,7 +89,7 @@ public class ResetGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; int error = 17; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index a37c0d86057..5d417b09192 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -81,7 +81,7 @@ public class SettingsGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) @@ -115,7 +115,7 @@ public class SettingsGenerateParseTest { errorRef.set(error); } - }); + }, 4096, 8192); Map settings1 = new HashMap<>(); settings1.put(13, 17); @@ -150,7 +150,7 @@ public class SettingsGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); Map settings1 = new HashMap<>(); int key = 13; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java index 3a8ef8dc07f..4bc408b01ce 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java @@ -48,7 +48,7 @@ public class WindowUpdateGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; int windowUpdate = 17; @@ -89,7 +89,7 @@ public class WindowUpdateGenerateParseTest frames.add(frame); return false; } - }); + }, 4096, 8192); int streamId = 13; int windowUpdate = 17; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 4a2ec08720c..ca2c440a563 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -22,7 +22,6 @@ package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; import org.eclipse.jetty.http.BadMessageException; -import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; @@ -47,13 +46,6 @@ public class HpackDecoder private final MetaDataBuilder _builder; private int _localMaxHeaderTableSize; - @Deprecated - public HpackDecoder() - { - this(4*1024,8*1024); - LOG.warn("USE HpackDecoder constructor with maxHeaderSize!!!"); - } - public HpackDecoder(int localMaxHeaderTableSize, int maxHeaderSize) { _context=new HpackContext(localMaxHeaderTableSize); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 67c485e60bd..d1306fa3d56 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -36,7 +36,7 @@ import org.eclipse.jetty.server.Connector; public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory { - private int headerTableSize = 4096; + private int maxHeaderTableSize = 4096; private int initialWindowSize = 65535; private int maxConcurrentStreams = -1; @@ -45,14 +45,14 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne super("h2-12"); } - public int getHeaderTableSize() + public int getMaxHeaderTableSize() { - return headerTableSize; + return maxHeaderTableSize; } - public void setHeaderTableSize(int headerTableSize) + public void setMaxHeaderTableSize(int maxHeaderTableSize) { - this.headerTableSize = headerTableSize; + this.maxHeaderTableSize = maxHeaderTableSize; } public int getInitialWindowSize() @@ -80,11 +80,11 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne { ServerSessionListener listener = newSessionListener(connector, endPoint); - Generator generator = new Generator(connector.getByteBufferPool(), getHeaderTableSize()); + Generator generator = new Generator(connector.getByteBufferPool(), getMaxHeaderTableSize()); HTTP2ServerSession session = new HTTP2ServerSession(endPoint, generator, listener, new HTTP2FlowControl(getInitialWindowSize()), getMaxConcurrentStreams()); - Parser parser = new ServerParser(connector.getByteBufferPool(), session); + Parser parser = newServerParser(connector.getByteBufferPool(), session); HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(), endPoint, parser, getInputBufferSize(), listener, session); @@ -93,6 +93,8 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint); + protected abstract ServerParser newServerParser(ByteBufferPool byteBufferPool, ServerParser.Listener listener); + private class HTTP2ServerConnection extends HTTP2Connection { private final ServerSessionListener listener; diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 61ccdce5583..29abe5fe40a 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -28,6 +28,8 @@ import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.http2.parser.ServerParser; +import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; @@ -54,6 +56,12 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF return new HTTPServerSessionListener(connector, httpConfiguration, endPoint); } + @Override + protected ServerParser newServerParser(ByteBufferPool byteBufferPool, ServerParser.Listener listener) + { + return new ServerParser(byteBufferPool, listener, getMaxHeaderTableSize(), httpConfiguration.getRequestHeaderSize()); + } + private class HTTPServerSessionListener extends ServerSessionListener.Adapter implements Stream.Listener { private final Connector connector; @@ -71,7 +79,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF public Map onPreface(Session session) { Map settings = new HashMap<>(); - settings.put(SettingsFrame.HEADER_TABLE_SIZE, getHeaderTableSize()); + settings.put(SettingsFrame.HEADER_TABLE_SIZE, getMaxHeaderTableSize()); settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialWindowSize()); int maxConcurrentStreams = getMaxConcurrentStreams(); if (maxConcurrentStreams >= 0) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java index ddf3d635009..5a441f30e39 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java @@ -19,6 +19,8 @@ package org.eclipse.jetty.http2.server; import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.parser.ServerParser; +import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; @@ -36,4 +38,11 @@ public class RawHTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnecti { return listener; } + + @Override + protected ServerParser newServerParser(ByteBufferPool byteBufferPool, ServerParser.Listener listener) + { + // TODO: make maxHeaderSize configurable. + return new ServerParser(byteBufferPool, listener, getMaxHeaderTableSize(), 8192); + } } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 872a41db431..68afb37a915 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -29,7 +29,6 @@ import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -131,7 +130,7 @@ public class HTTP2ServerTest latch.countDown(); return false; } - }); + }, 4096, 8192); parseResponse(client, parser); @@ -187,7 +186,7 @@ public class HTTP2ServerTest latch.countDown(); return false; } - }); + }, 4096, 8192); parseResponse(client, parser); @@ -259,7 +258,7 @@ public class HTTP2ServerTest latch.countDown(); return false; } - }); + }, 4096, 8192); parseResponse(client, parser); @@ -308,7 +307,7 @@ public class HTTP2ServerTest latch.countDown(); return false; } - }); + }, 4096, 8192); parseResponse(client, parser); @@ -348,7 +347,7 @@ public class HTTP2ServerTest latch.countDown(); return false; } - }); + }, 4096, 8192); parseResponse(client, parser); From 9d9260e634560a227fbe97b1b57643f7ce641876 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 18 Jun 2014 13:57:37 +0200 Subject: [PATCH 111/269] Implemented idle timeout functionality for streams. --- .../jetty/http2/client/HTTP2Client.java | 2 +- .../http2/client/HTTP2ClientSession.java | 7 +- .../jetty/http2/client/IdleTimeoutTest.java | 169 ++++++++++++++++++ .../org/eclipse/jetty/http2/HTTP2Session.java | 95 +++++++--- .../org/eclipse/jetty/http2/HTTP2Stream.java | 79 ++++++-- .../org/eclipse/jetty/http2/ISession.java | 2 + .../org/eclipse/jetty/http2/api/Stream.java | 4 + .../AbstractHTTP2ServerConnectionFactory.java | 2 +- .../http2/server/HTTP2ServerSession.java | 7 +- 9 files changed, 325 insertions(+), 42 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index c9c0735085a..f69e549ecb5 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -129,7 +129,7 @@ public class HTTP2Client extends ContainerLifeCycle { Context context = (Context)attachment; Generator generator = new Generator(byteBufferPool, 4096); - HTTP2Session session = new HTTP2ClientSession(endpoint, generator, context.listener, new HTTP2FlowControl(65535)); + HTTP2Session session = new HTTP2ClientSession(getScheduler(), endpoint, generator, context.listener, new HTTP2FlowControl(65535)); Parser parser = new Parser(byteBufferPool, session, 4096, 8192); return new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, 8192, context.promise, session); } diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index 1ddf8e09bb6..7d0affde032 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -30,14 +30,15 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.Scheduler; public class HTTP2ClientSession extends HTTP2Session { private static final Logger LOG = Log.getLogger(HTTP2ClientSession.class); - public HTTP2ClientSession(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl) + public HTTP2ClientSession(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl) { - super(endPoint, generator, listener, flowControl, -1, 1); + super(scheduler, endPoint, generator, listener, flowControl, -1, 1); } @Override @@ -48,7 +49,7 @@ public class HTTP2ClientSession extends HTTP2Session if (stream == null) { ResetFrame reset = new ResetFrame(streamId, ErrorCode.STREAM_CLOSED_ERROR); - reset(reset, disconnectCallback); + reset(reset, disconnectOnFailure()); } else { diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java index b392af4e766..d229967214e 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java @@ -19,8 +19,15 @@ package org.eclipse.jetty.http2.client; +import java.io.IOException; +import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; @@ -28,13 +35,18 @@ import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.junit.Assert; import org.junit.Test; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertThat; + public class IdleTimeoutTest extends AbstractTest { private final int idleTimeout = 1000; @@ -250,4 +262,161 @@ public class IdleTimeoutTest extends AbstractTest Assert.assertFalse(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS)); } + + @Test + public void testClientEnforcingStreamIdleTimeout() throws Exception + { + final int idleTimeout = 1000; + startServer(new HttpServlet() + { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + try + { + Thread.sleep(2 * idleTimeout); + } + catch (InterruptedException x) + { + throw new RuntimeException(x); + } + } + }); + + Session session = newClient(new Session.Listener.Adapter()); + + final CountDownLatch dataLatch = new CountDownLatch(1); + final CountDownLatch timeoutLatch = new CountDownLatch(1); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + session.newStream(requestFrame, new Promise.Adapter() + { + @Override + public void succeeded(Stream stream) + { + stream.setIdleTimeout(idleTimeout); + } + }, new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + dataLatch.countDown(); + } + + @Override + public void onFailure(Stream stream, Throwable x) + { + assertThat(x, instanceOf(TimeoutException.class)); + timeoutLatch.countDown(); + } + }); + + Assert.assertTrue(timeoutLatch.await(5, TimeUnit.SECONDS)); + // We must not receive any DATA frame. + Assert.assertFalse(dataLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + // Stream must be gone. + Assert.assertTrue(session.getStreams().isEmpty()); + } + + @Test + public void testServerEnforcingStreamIdleTimeout() throws Exception + { + final CountDownLatch timeoutLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + stream.setIdleTimeout(idleTimeout); + return new Stream.Listener.Adapter() + { + @Override + public void onFailure(Stream stream, Throwable x) + { + timeoutLatch.countDown(); + } + }; + } + }); + + final CountDownLatch resetLatch = new CountDownLatch(1); + Session session = newClient(new Session.Listener.Adapter() + { + @Override + public void onReset(Session session, ResetFrame frame) + { + resetLatch.countDown(); + } + }); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + // Stream does not end here, but we won't send any DATA frame. + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, false); + session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + + Assert.assertTrue(timeoutLatch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); + // Stream must be gone. + Assert.assertTrue(session.getStreams().isEmpty()); + } + + @Test + public void testIdleTimeoutIsInterruptedWhenReceiving() throws Exception + { + final CountDownLatch timeoutLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + stream.setIdleTimeout(idleTimeout); + return new Stream.Listener.Adapter() + { + @Override + public void onFailure(Stream stream, Throwable x) + { + timeoutLatch.countDown(); + } + }; + } + }); + + Session session = newClient(new Session.Listener.Adapter()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, false); + session.newStream(requestFrame, new Promise.Adapter() + { + @Override + public void succeeded(final Stream stream) + { + sleep(idleTimeout / 2); + stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), false), new Callback.Adapter() + { + private int sends; + + @Override + public void succeeded() + { + sleep(idleTimeout / 2); + boolean last = ++sends == 2; + stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), last), last ? INSTANCE : this); + } + }); + } + }, new Stream.Listener.Adapter()); + + Assert.assertFalse(timeoutLatch.await(1, TimeUnit.SECONDS)); + } + + private void sleep(long value) + { + try + { + TimeUnit.MILLISECONDS.sleep(value); + } + catch (InterruptedException x) + { + Assert.fail(); + } + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index f6013ca2dff..3c4931907bb 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -59,12 +59,13 @@ import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.Scheduler; public abstract class HTTP2Session implements ISession, Parser.Listener { private static final Logger LOG = Log.getLogger(HTTP2Session.class); - protected final Callback disconnectCallback = new Callback.Adapter() + private final Callback disconnectOnFailure = new Callback.Adapter() { @Override public void failed(Throwable x) @@ -72,13 +73,13 @@ public abstract class HTTP2Session implements ISession, Parser.Listener disconnect(); } }; - private final ConcurrentMap streams = new ConcurrentHashMap<>(); private final AtomicInteger streamIds = new AtomicInteger(); private final AtomicInteger lastStreamId = new AtomicInteger(); private final AtomicInteger streamCount = new AtomicInteger(); private final AtomicInteger windowSize = new AtomicInteger(); private final AtomicBoolean closed = new AtomicBoolean(); + private final Scheduler scheduler; private final EndPoint endPoint; private final Generator generator; private final Listener listener; @@ -86,8 +87,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final Flusher flusher; private volatile int maxStreamCount; - public HTTP2Session(EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int maxStreams, int initialStreamId) + public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int maxStreams, int initialStreamId) { + this.scheduler = scheduler; this.endPoint = endPoint; this.generator = generator; this.listener = listener; @@ -103,16 +105,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return generator; } - public int getMaxStreamCount() - { - return maxStreamCount; - } - - public FlowControl getFlowControl() - { - return flowControl; - } - @Override public boolean onData(final DataFrame frame) { @@ -140,7 +132,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener else { ResetFrame resetFrame = new ResetFrame(streamId, ErrorCode.STREAM_CLOSED_ERROR); - reset(resetFrame, disconnectCallback); + reset(resetFrame, disconnectOnFailure()); return false; } } @@ -157,6 +149,18 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onReset(ResetFrame frame) { + if (LOG.isDebugEnabled()) + LOG.debug("Received {}", frame); + + IStream stream = getStream(frame.getStreamId()); + if (stream != null) + stream.process(frame, Callback.Adapter.INSTANCE); + + notifyReset(this, frame); + + if (stream != null) + removeStream(stream, false); + return false; } @@ -186,7 +190,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener // SPEC: SETTINGS frame MUST be replied. SettingsFrame reply = new SettingsFrame(Collections.emptyMap(), true); - settings(reply, disconnectCallback); + settings(reply, disconnectOnFailure()); return false; } @@ -209,7 +213,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener else { PingFrame reply = new PingFrame(frame.getPayload(), true); - control(null, reply, disconnectCallback); + control(null, reply, disconnectOnFailure()); } return false; } @@ -265,7 +269,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void onConnectionFailure(int error, String reason) { - close(error, reason, disconnectCallback); + close(error, reason, disconnectOnFailure()); } @Override @@ -314,7 +318,15 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void reset(ResetFrame frame, Callback callback) { - control(null, frame, callback); + if (closed.get()) + { + callback.succeeded(); + } + else + { + // TODO: think about moving reset() to Stream. + control(getStream(frame.getStreamId()), frame, callback); + } } @Override @@ -352,7 +364,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.iterate(); } - protected void disconnect() + public void disconnect() { if (LOG.isDebugEnabled()) LOG.debug("Disconnecting"); @@ -365,6 +377,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener int streamId = stream.getId(); if (streams.putIfAbsent(streamId, stream) == null) { + stream.setIdleTimeout(endPoint.getIdleTimeout()); flowControl.onNewStream(stream); if (LOG.isDebugEnabled()) LOG.debug("Created local {}", stream); @@ -387,7 +400,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener int maxStreams = maxStreamCount; if (maxStreams >= 0 && currentStreams >= maxStreams) { - reset(new ResetFrame(streamId, ErrorCode.PROTOCOL_ERROR), disconnectCallback); + reset(new ResetFrame(streamId, ErrorCode.PROTOCOL_ERROR), disconnectOnFailure()); return null; } if (streamCount.compareAndSet(currentStreams, currentStreams + 1)) @@ -400,6 +413,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (streams.putIfAbsent(streamId, stream) == null) { updateLastStreamId(streamId); + stream.setIdleTimeout(endPoint.getIdleTimeout()); flowControl.onNewStream(stream); if (LOG.isDebugEnabled()) LOG.debug("Created remote {}", stream); @@ -407,14 +421,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } else { - close(ErrorCode.PROTOCOL_ERROR, "duplicate_stream", disconnectCallback); + close(ErrorCode.PROTOCOL_ERROR, "duplicate_stream", disconnectOnFailure()); return null; } } protected IStream newStream(HeadersFrame frame) { - return new HTTP2Stream(this, frame); + return new HTTP2Stream(scheduler, this, frame); } protected void removeStream(IStream stream, boolean local) @@ -461,6 +475,11 @@ public abstract class HTTP2Session implements ISession, Parser.Listener Atomics.updateMax(lastStreamId, streamId); } + protected Callback disconnectOnFailure() + { + return disconnectOnFailure; + } + protected Stream.Listener notifyNewStream(Stream stream, HeadersFrame frame) { try @@ -498,6 +517,18 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } + protected void notifyReset(Session session, ResetFrame frame) + { + try + { + listener.onReset(session, frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } + protected void notifyClose(Session session, GoAwayFrame frame) { try @@ -755,6 +786,24 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void succeeded() { + switch (frame.getType()) + { + case RST_STREAM: + { + if (stream != null) + removeStream(stream, true); + break; + } + case GO_AWAY: + { + disconnect(); + break; + } + default: + { + break; + } + } callback.succeeded(); } @@ -812,7 +861,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener stream.updateClose(dataFrame.isEndStream(), true); if (stream.isClosed()) removeStream(stream, true); - super.succeeded(); + callback.succeeded(); } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 4133d77bd1d..9da557c4a4e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -20,30 +20,45 @@ package org.eclipse.jetty.http2; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.parser.ErrorCode; +import org.eclipse.jetty.io.IdleTimeout; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.Scheduler; -public class HTTP2Stream implements IStream +public class HTTP2Stream extends IdleTimeout implements IStream { private static final Logger LOG = Log.getLogger(HTTP2Stream.class); + private final Callback disconnectOnFailure = new Callback.Adapter() + { + @Override + public void failed(Throwable x) + { + session.disconnect(); + } + }; private final AtomicReference> attributes = new AtomicReference<>(); private final AtomicReference closeState = new AtomicReference<>(CloseState.NOT_CLOSED); private final AtomicInteger windowSize = new AtomicInteger(); private final ISession session; private final HeadersFrame frame; - private Listener listener; + private volatile Listener listener; private volatile boolean reset = false; - public HTTP2Stream(ISession session, HeadersFrame frame) + public HTTP2Stream(Scheduler scheduler, ISession session, HeadersFrame frame) { + super(scheduler); this.session = session; this.frame = frame; } @@ -102,6 +117,28 @@ public class HTTP2Stream implements IStream return closeState.get() == CloseState.CLOSED; } + @Override + public boolean isOpen() + { + return !isClosed(); + } + + @Override + protected void onIdleExpired(TimeoutException timeout) + { + if (LOG.isDebugEnabled()) + LOG.debug("Idle timeout {}ms expired on {}", getIdleTimeout(), this); + + // The stream is now gone, we must close it to + // avoid that its idle timeout is rescheduled. + closeState.set(CloseState.CLOSED); + onClose(); + + session.reset(new ResetFrame(getId(), ErrorCode.CANCEL_STREAM_ERROR), disconnectOnFailure); + + notifyFailure(this, timeout); + } + private ConcurrentMap attributes() { ConcurrentMap map = attributes.get(); @@ -131,14 +168,21 @@ public class HTTP2Stream implements IStream @Override public boolean process(Frame frame, Callback callback) { + notIdle(); + switch (frame.getType()) { case DATA: { - return notifyData((DataFrame)frame, callback); + // TODO: handle cases where: + // TODO: A) stream already remotely close. + // TODO: B) DATA before HEADERS. + notifyData(this, (DataFrame)frame, callback); + return false; } case HEADERS: { + // TODO: handle case where HEADERS after DATA. return false; } case RST_STREAM: @@ -210,28 +254,41 @@ public class HTTP2Stream implements IStream return windowSize.getAndAdd(delta); } - protected boolean notifyData(DataFrame frame, Callback callback) + protected void notifyData(Stream stream, DataFrame frame, Callback callback) { final Listener listener = this.listener; if (listener == null) - return false; + return; try { - listener.onData(this, frame, callback); - return false; + listener.onData(stream, frame, callback); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } + + private void notifyFailure(Stream stream, Throwable failure) + { + Listener listener = this.listener; + if (listener == null) + return; + try + { + listener.onFailure(stream, failure); } catch (Throwable x) { LOG.info("Failure while notifying listener " + listener, x); - return false; } } @Override public String toString() { - return String.format("%s@%x{id=%d,windowSize=%s,%s}", getClass().getSimpleName(), - hashCode(), getId(), windowSize, closeState); + return String.format("%s@%x{id=%d,windowSize=%s,reset=%b,%s}", getClass().getSimpleName(), + hashCode(), getId(), windowSize, reset, closeState); } private enum CloseState diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index bd39cdb2602..d072c3f9075 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -33,4 +33,6 @@ public interface ISession extends Session public void data(IStream stream, DataFrame frame, Callback callback); public int updateWindowSize(int delta); + + public void disconnect(); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index 5e72e05464a..b6af7e71e7f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -42,6 +42,10 @@ public interface Stream public boolean isClosed(); + public long getIdleTimeout(); + + public void setIdleTimeout(long idleTimeout); + // TODO: see SPDY's Stream public interface Listener diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index d1306fa3d56..e515d45c124 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -81,7 +81,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne ServerSessionListener listener = newSessionListener(connector, endPoint); Generator generator = new Generator(connector.getByteBufferPool(), getMaxHeaderTableSize()); - HTTP2ServerSession session = new HTTP2ServerSession(endPoint, generator, listener, + HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, generator, listener, new HTTP2FlowControl(getInitialWindowSize()), getMaxConcurrentStreams()); Parser parser = newServerParser(connector.getByteBufferPool(), session); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index e721da5e44a..0bea5ad677c 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -35,6 +35,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.Scheduler; public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Listener { @@ -42,9 +43,9 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis private final ServerSessionListener listener; - public HTTP2ServerSession(EndPoint endPoint, Generator generator, ServerSessionListener listener, FlowControl flowControl, int maxStreams) + public HTTP2ServerSession(Scheduler scheduler, EndPoint endPoint, Generator generator, ServerSessionListener listener, FlowControl flowControl, int maxStreams) { - super(endPoint, generator, listener, flowControl, maxStreams, 2); + super(scheduler, endPoint, generator, listener, flowControl, maxStreams, 2); this.listener = listener; } @@ -56,7 +57,7 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis if (settings == null) settings = Collections.emptyMap(); SettingsFrame frame = new SettingsFrame(settings, false); - settings(frame, disconnectCallback); + settings(frame, disconnectOnFailure()); return false; } From beb5918c3cb57f8df333aa375009024f3b7159c4 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 18 Jun 2014 13:58:17 +0200 Subject: [PATCH 112/269] fixed client --- .../test/java/org/eclipse/jetty/http2/client/AbstractTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java index 1f0cff2e03b..8dc0afe68f4 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.client; import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; + import javax.servlet.http.HttpServlet; import org.eclipse.jetty.http.HostPortHttpField; From 9acf971cc17fc593ebfff0334a3c6f691992b95d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 18 Jun 2014 15:26:33 +0200 Subject: [PATCH 113/269] cache path URI in table --- .../src/main/java/org/eclipse/jetty/http/MetaData.java | 7 ++++++- .../java/org/eclipse/jetty/http2/hpack/HpackDecoder.java | 8 ++++++++ .../org/eclipse/jetty/http2/hpack/MetaDataBuilder.java | 9 +++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index 8267ee0db4e..680d1c4371c 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -116,10 +116,15 @@ public class MetaData implements Iterable } public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, String path, HttpFields fields) + { + this(version,scheme,method,authority,new HttpURI(path),fields); + } + + public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, HttpURI path, HttpFields fields) { super(version,fields); _method=method; - _uri=new HttpURI(path); // TODO - this is not so efficient! + _uri=path; _hostPort = authority; _scheme=scheme; } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index ca2c440a563..136bb8541d3 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.TypeUtil; @@ -185,6 +186,13 @@ public class HpackDecoder field = new AuthorityHttpField(value); break; + case ":path": + if (indexed) + field = new StaticValueHttpField(header,name,value,new HttpURI(value)); + else + field = new HttpField(header,name,value); + break; + default: field = new HttpField(header,name,value); break; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 2ff9510b32a..b130ee86bac 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -40,7 +41,7 @@ public class MetaDataBuilder private String _method; private HttpScheme _scheme; private HostPortHttpField _authority; - private String _path; + private HttpURI _path; private HttpFields _fields = new HttpFields(10); @@ -89,6 +90,10 @@ public class MetaDataBuilder _scheme = (HttpScheme)value.getStaticValue(); break; + case ":path": + _path = (HttpURI)value.getStaticValue(); + break; + default: throw new IllegalArgumentException(); } @@ -114,7 +119,7 @@ public class MetaDataBuilder break; case ":path": - _path=field.getValue(); + _path=new HttpURI(field.getValue()); break; default: From 14dba64164f668a4dffb92fb94ac03e74616cb66 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 18 Jun 2014 15:24:06 +0200 Subject: [PATCH 114/269] Fixed handling of zero-length hpacked headers. --- .../jetty/http2/parser/HeadersBodyParser.java | 7 ++----- .../jetty/http2/parser/PushPromiseBodyParser.java | 15 ++++----------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 17e33b43d75..1fd9a0a0393 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -164,7 +164,7 @@ public class HeadersBodyParser extends BodyParser { streamId &= 0x7F_FF_FF_FF; state = State.WEIGHT; - if (length <= 0) + if (length < 1) { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); } @@ -176,10 +176,7 @@ public class HeadersBodyParser extends BodyParser weight = buffer.get() & 0xFF; --length; state = State.HEADERS; - if (length <= 0) - { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); - } + loop = length == 0; break; } case HEADERS: diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java index fd1a101515d..dd0a7ae3715 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -20,8 +20,8 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; -import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; public class PushPromiseBodyParser extends BodyParser { @@ -94,8 +94,7 @@ public class PushPromiseBodyParser extends BodyParser --length; length -= paddingLength; state = State.STREAM_ID; - loop = length == 0; - if (length < 0) + if (length < 4) { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame_padding"); } @@ -109,10 +108,7 @@ public class PushPromiseBodyParser extends BodyParser streamId &= 0x7F_FF_FF_FF; length -= 4; state = State.HEADERS; - if (length < 1) - { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); - } + loop = length == 0; } else { @@ -135,10 +131,7 @@ public class PushPromiseBodyParser extends BodyParser { streamId &= 0x7F_FF_FF_FF; state = State.HEADERS; - if (length <= 0) - { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); - } + loop = length == 0; } break; } From 42116530951f11981adc9db323f63b6864f696f8 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 18 Jun 2014 15:24:16 +0200 Subject: [PATCH 115/269] Fixed tests. --- .../jetty/http2/client/IdleTimeoutTest.java | 77 +++++++++++++++++-- .../test/resources/jetty-logging.properties | 10 +-- .../jetty/http2/server/HTTP2ServerTest.java | 15 +--- .../test/resources/jetty-logging.properties | 1 - 4 files changed, 74 insertions(+), 29 deletions(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java index d229967214e..857e50190d2 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java @@ -59,6 +59,7 @@ public class IdleTimeoutTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { + stream.setIdleTimeout(10 * idleTimeout); MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -79,7 +80,14 @@ public class IdleTimeoutTest extends AbstractTest MetaData.Request metaData = newRequest("GET", new HttpFields()); HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); - session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + session.newStream(requestFrame, new Promise.Adapter() + { + @Override + public void succeeded(Stream stream) + { + stream.setIdleTimeout(10 * idleTimeout); + } + }, new Stream.Listener.Adapter()); Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); } @@ -87,7 +95,15 @@ public class IdleTimeoutTest extends AbstractTest @Test public void testServerEnforcingIdleTimeoutWithUnrespondedStream() throws Exception { - startServer(new ServerSessionListener.Adapter()); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + stream.setIdleTimeout(10 * idleTimeout); + return null; + } + }); connector.setIdleTimeout(idleTimeout); final CountDownLatch latch = new CountDownLatch(1); @@ -103,7 +119,14 @@ public class IdleTimeoutTest extends AbstractTest // The request is not replied, and the server should idle timeout. MetaData.Request metaData = newRequest("GET", new HttpFields()); HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); - session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + session.newStream(requestFrame, new Promise.Adapter() + { + @Override + public void succeeded(Stream stream) + { + stream.setIdleTimeout(10 * idleTimeout); + } + }, new Stream.Listener.Adapter()); Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); } @@ -118,6 +141,7 @@ public class IdleTimeoutTest extends AbstractTest { try { + stream.setIdleTimeout(10 * idleTimeout); Thread.sleep(2 * idleTimeout); MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); @@ -146,7 +170,14 @@ public class IdleTimeoutTest extends AbstractTest final CountDownLatch replyLatch = new CountDownLatch(1); MetaData.Request metaData = newRequest("GET", new HttpFields()); HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); - session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter() + session.newStream(requestFrame, new Promise.Adapter() + { + @Override + public void succeeded(Stream stream) + { + stream.setIdleTimeout(10 * idleTimeout); + } + }, new Stream.Listener.Adapter() { @Override public void onHeaders(Stream stream, HeadersFrame frame) @@ -170,6 +201,7 @@ public class IdleTimeoutTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { + stream.setIdleTimeout(10 * idleTimeout); MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -187,7 +219,14 @@ public class IdleTimeoutTest extends AbstractTest Session session = newClient(new Session.Listener.Adapter()); MetaData.Request metaData = newRequest("GET", new HttpFields()); HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); - session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + session.newStream(requestFrame, new Promise.Adapter() + { + @Override + public void succeeded(Stream stream) + { + stream.setIdleTimeout(10 * idleTimeout); + } + }, new Stream.Listener.Adapter()); Assert.assertTrue(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); } @@ -198,6 +237,13 @@ public class IdleTimeoutTest extends AbstractTest final CountDownLatch closeLatch = new CountDownLatch(1); startServer(new ServerSessionListener.Adapter() { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + stream.setIdleTimeout(10 * idleTimeout); + return null; + } + @Override public void onClose(Session session, GoAwayFrame frame) { @@ -209,7 +255,14 @@ public class IdleTimeoutTest extends AbstractTest Session session = newClient(new Session.Listener.Adapter()); MetaData.Request metaData = newRequest("GET", new HttpFields()); HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); - session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter()); + session.newStream(requestFrame, new Promise.Adapter() + { + @Override + public void succeeded(Stream stream) + { + stream.setIdleTimeout(10 * idleTimeout); + } + }, new Stream.Listener.Adapter()); Assert.assertTrue(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); } @@ -223,6 +276,7 @@ public class IdleTimeoutTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { + stream.setIdleTimeout(10 * idleTimeout); MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -242,7 +296,14 @@ public class IdleTimeoutTest extends AbstractTest final CountDownLatch replyLatch = new CountDownLatch(1); MetaData.Request metaData = newRequest("GET", new HttpFields()); HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); - session.newStream(requestFrame, new Promise.Adapter(), new Stream.Listener.Adapter() + session.newStream(requestFrame, new Promise.Adapter() + { + @Override + public void succeeded(Stream stream) + { + stream.setIdleTimeout(10 * idleTimeout); + } + }, new Stream.Listener.Adapter() { @Override public void onHeaders(Stream stream, HeadersFrame frame) @@ -361,7 +422,7 @@ public class IdleTimeoutTest extends AbstractTest } @Test - public void testIdleTimeoutIsInterruptedWhenReceiving() throws Exception + public void testStreamIdleTimeoutIsNotEnforcedWhenReceiving() throws Exception { final CountDownLatch timeoutLatch = new CountDownLatch(1); startServer(new ServerSessionListener.Adapter() diff --git a/jetty-http2/http2-common/src/test/resources/jetty-logging.properties b/jetty-http2/http2-common/src/test/resources/jetty-logging.properties index 31b37987e9a..b4e43807801 100644 --- a/jetty-http2/http2-common/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-common/src/test/resources/jetty-logging.properties @@ -1,10 +1,2 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.LEVEL=INFO -org.eclipse.jetty.STACKS=true -org.eclipse.jetty.SOURCE=false -org.eclipse.jetty.http2.hpack.LEVEL=debug -#org.eclipse.jetty.spdy.LEVEL=DEBUG -#org.eclipse.jetty.server.LEVEL=DEBUG -#org.eclipse.jetty.io.LEVEL=DEBUG -#org.eclipse.jetty.io.ssl.LEVEL=DEBUG -#org.eclipse.jetty.spdy.server.LEVEL=DEBUG +org.eclipse.jetty.http2.LEVEL=INFO diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 68afb37a915..92a45734bb8 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.http2.server; -import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -46,9 +45,6 @@ import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.hpack.HpackContext; -import org.eclipse.jetty.http2.hpack.HpackDecoder; -import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.PrefaceParser; @@ -86,9 +82,6 @@ public class HTTP2ServerTest generator = new Generator(byteBufferPool); server.start(); - HpackContext.LOG.setDebugEnabled(true); - HpackEncoder.LOG.setDebugEnabled(true); - HpackDecoder.LOG.setDebugEnabled(true); } @After @@ -355,7 +348,7 @@ public class HTTP2ServerTest } } - private void parseResponse(Socket client, Parser parser) throws IOException + private boolean parseResponse(Socket client, Parser parser) throws IOException { byte[] buffer = new byte[2048]; InputStream input = client.getInputStream(); @@ -365,13 +358,13 @@ public class HTTP2ServerTest try { int read = input.read(buffer); - if (read <= 0) - throw new EOFException(); + if (read < 0) + return true; parser.parse(ByteBuffer.wrap(buffer, 0, read)); } catch (SocketTimeoutException x) { - break; + return false; } } } diff --git a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties index 1a5ad20f950..3d1e404e15a 100644 --- a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties @@ -1,4 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog org.eclipse.jetty.http2.LEVEL=INFO -org.eclipse.jetty.http2.hpack.LEVEL=DEBUG From c0629b6e04f4182dade9e7f4e70205ffff13961e Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 19 Jun 2014 15:32:27 +0200 Subject: [PATCH 116/269] encoding debug --- .../main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 8f6574cfa43..1ba7ae3adf0 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -209,6 +209,7 @@ public class HpackEncoder { // entries like :status: 200 and :method: GET are worthwhile putting into ref set. // as they are likely to be repeated. + encoding="StaticIndexed"; int index=_context.index(entry); buffer.put((byte)0x80); NBitInteger.encode(buffer,7,index); From 9d44c32c93805ac012c6132b9786d5d9e45ce79b Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 16 Jun 2014 18:11:40 +0200 Subject: [PATCH 117/269] Added ALPN debug configuration. --- .../src/main/config/etc/protonego-alpn.xml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml index 293de040bca..5d2ac7ae2c2 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml +++ b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml @@ -3,14 +3,17 @@ - - spdy/3 - spdy/2 - http/1.1 - + + spdy/3 + spdy/2 + http/1.1 + - + http/1.1 + + + From e48cdb519b227bdad06edd96dbdb60581d0cea28 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 19 Jun 2014 10:18:51 -0700 Subject: [PATCH 118/269] 437395 - Start / Properties in template sections should be default applied for enabled modules + Fixing typo in enableModule() + Fixing concurrent modification exception during walk of parents in enableModule() --- .../java/org/eclipse/jetty/start/Module.java | 5 +- .../java/org/eclipse/jetty/start/Modules.java | 29 ++++++-- .../org/eclipse/jetty/start/MainTest.java | 25 +++++++ .../org/eclipse/jetty/start/ModulesTest.java | 11 +-- .../eclipse/jetty/start/TestBadUseCases.java | 4 +- .../org/eclipse/jetty/start/TestUseCases.java | 2 +- .../test/resources/assert-home-with-spdy.txt | 71 +++++++++++++++++++ .../resources/usecases/assert-enable-spdy.txt | 18 ++++- .../usecases/home/etc/protonego-alpn.xml | 0 .../usecases/home/etc/protonego-npn.xml | 0 .../resources/usecases/home/modules/npn.mod | 4 -- .../modules/protonego-impl/alpn-1.7.0_40.mod | 8 +++ .../modules/protonego-impl/alpn-1.7.0_45.mod | 8 +++ .../modules/protonego-impl/alpn-1.7.0_51.mod | 8 +++ .../modules/protonego-impl/alpn-1.7.0_55.mod | 8 +++ .../modules/protonego-impl/alpn-1.7.0_60.mod | 8 +++ .../modules/protonego-impl/alpn-1.8.0.mod | 8 +++ .../modules/protonego-impl/alpn-1.8.0_05.mod | 8 +++ .../home/modules/protonego-impl/alpn.mod | 36 ++++++++++ .../{npn => protonego-impl}/npn-1.7.0_04.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_05.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_06.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_07.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_09.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_10.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_11.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_13.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_15.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_17.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_21.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_25.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_40.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_45.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_51.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_55.mod | 2 +- .../{npn => protonego-impl}/npn-1.7.0_60.mod | 2 +- .../home/modules/protonego-impl/npn.mod | 31 ++++++++ .../usecases/home/modules/protonego.mod | 15 ++++ .../resources/usecases/home/modules/spdy.mod | 19 ++++- .../resources/usecases/home/modules/ssl.mod | 35 +++++++++ 40 files changed, 356 insertions(+), 39 deletions(-) create mode 100644 jetty-start/src/test/resources/assert-home-with-spdy.txt create mode 100644 jetty-start/src/test/resources/usecases/home/etc/protonego-alpn.xml create mode 100644 jetty-start/src/test/resources/usecases/home/etc/protonego-npn.xml delete mode 100644 jetty-start/src/test/resources/usecases/home/modules/npn.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_04.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_05.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_06.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_07.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_09.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_10.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_11.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_13.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_15.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_17.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_21.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_25.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_40.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_45.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_51.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_55.mod (93%) rename jetty-start/src/test/resources/usecases/home/modules/{npn => protonego-impl}/npn-1.7.0_60.mod (93%) create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/protonego.mod create mode 100644 jetty-start/src/test/resources/usecases/home/modules/ssl.mod diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java index 17a3317f802..dc0de1ced59 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java @@ -402,7 +402,10 @@ public class Module { StringBuilder str = new StringBuilder(); str.append("Module[").append(logicalName); - str.append(",").append(fileRef); + if (!logicalName.equals(fileRef)) + { + str.append(",file=").append(fileRef); + } if (enabled) { str.append(",enabled"); diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java index 40406894c58..804d63ae325 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java @@ -271,13 +271,30 @@ public class Modules implements Iterable { // A regex! Pattern pat = Pattern.compile(name); - for (Map.Entry entry : modules.entrySet()) + List matching = new ArrayList<>(); + do { - if (pat.matcher(entry.getKey()).matches()) + matching.clear(); + + // find matching entries that are not enabled + for (Map.Entry entry : modules.entrySet()) { - enableModule(entry.getValue(),sources); + if (pat.matcher(entry.getKey()).matches()) + { + if (!entry.getValue().isEnabled()) + { + matching.add(entry.getValue()); + } + } + } + + // enable them + for (Module module : matching) + { + enableModule(module,sources); } } + while (!matching.isEmpty()); } else { @@ -309,10 +326,12 @@ public class Modules implements Iterable } // enable any parents that haven't been enabled (yet) - for(String name: module.getParentNames()) + Set parentNames = new HashSet<>(); + parentNames.addAll(module.getParentNames()); + for(String name: parentNames) { Module parent = modules.get(name); - if (name == null) + if (parent == null) { // parent module doesn't exist, yet Path file = baseHome.getPath("modules/" + name + ".mod"); diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java index 2043d6b5ae9..1f436b2cf3a 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java @@ -133,6 +133,31 @@ public class MainTest ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-jvm.txt"); } + + @Test + public void testWithSpdy() throws Exception + { + List cmdLineArgs = new ArrayList<>(); + + File homePath = MavenTestingUtils.getTestResourceDir("usecases/home").getAbsoluteFile(); + cmdLineArgs.add("jetty.home=" + homePath); + cmdLineArgs.add("user.dir=" + homePath); + + // Modules + cmdLineArgs.add("--module=server"); + cmdLineArgs.add("--module=deploy"); + cmdLineArgs.add("--module=spdy"); + + Main main = new Main(); + + StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()])); + BaseHome baseHome = main.getBaseHome(); + + Assert.assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath())); + Assert.assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath())); + + ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-spdy.txt"); + } @Test public void testJettyHomeWithSpaces() throws Exception diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java index b7c0468442c..506ad932ce0 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java @@ -87,7 +87,6 @@ public class ModulesTest expected.add("deploy"); expected.add("debug"); expected.add("security"); - expected.add("npn"); expected.add("ext"); expected.add("websocket"); expected.add("rewrite"); @@ -104,6 +103,8 @@ public class ModulesTest // (only present if enabled) expected.add("jsp-impl"); expected.add("monitor"); expected.add("xml"); + expected.add("ssl"); + expected.add("protonego"); expected.add("servlet"); expected.add("jaas"); expected.add("http"); @@ -122,7 +123,7 @@ public class ModulesTest // Test Env File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home"); File baseDir = testdir.getEmptyDir(); - String cmdLine[] = new String[] {"jetty.version=TEST", "java.version=1.7.0_21"}; + String cmdLine[] = new String[] {"jetty.version=TEST", "java.version=1.7.0_60"}; // Configuration CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine); @@ -155,8 +156,10 @@ public class ModulesTest expected.add("server"); // transitive expected.add("base"); - expected.add("npn"); - expected.add("npn-boot"); + expected.add("ssl"); + expected.add("protonego"); + expected.add("protonego-boot"); + expected.add("protonego-impl"); expected.add("xml"); expected.add("jsp-impl"); diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java b/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java index 8af10ece13a..9280cdab156 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java @@ -77,8 +77,8 @@ public class TestBadUseCases public void testWithSpdyBadNpnVersion() throws Exception { assertBadConfig("home","base.enable.spdy.bad.npn.version", - "Missing referenced dependency: npn/npn-1.7.0_01", - "java.version=1.7.0_01"); + "Missing referenced dependency: protonego-impl/npn-1.7.0_01", + "java.version=1.7.0_01", "protonego=npn"); } diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java index 3cfa5445ac6..bf77b48141d 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java @@ -106,7 +106,7 @@ public class TestUseCases @Test public void testWithSpdy() throws Exception { - assertUseCase("home","base.enable.spdy","assert-enable-spdy.txt","java.version=1.7.0_21"); + assertUseCase("home","base.enable.spdy","assert-enable-spdy.txt","java.version=1.7.0_60"); } @Test diff --git a/jetty-start/src/test/resources/assert-home-with-spdy.txt b/jetty-start/src/test/resources/assert-home-with-spdy.txt new file mode 100644 index 00000000000..7eddc13f688 --- /dev/null +++ b/jetty-start/src/test/resources/assert-home-with-spdy.txt @@ -0,0 +1,71 @@ +# The XMLs we expect (order is important) +XML|${jetty.base}/etc/jetty-jmx.xml +XML|${jetty.base}/etc/protonego-alpn.xml +XML|${jetty.base}/etc/jetty.xml +XML|${jetty.base}/etc/jetty-http.xml +XML|${jetty.base}/etc/jetty-ssl.xml +XML|${jetty.base}/etc/jetty-plus.xml +XML|${jetty.base}/etc/jetty-spdy.xml +XML|${jetty.base}/etc/jetty-annotations.xml +XML|${jetty.base}/etc/jetty-deploy.xml +XML|${jetty.base}/etc/jetty-websockets.xml + +# The LIBs we expect (order is irrelevant) +LIB|${jetty.base}/lib/annotations/javax.annotation-api-1.2.jar +LIB|${jetty.base}/lib/annotations/org.objectweb.asm-TEST.jar +LIB|${jetty.base}/lib/jetty-annotations-TEST.jar +LIB|${jetty.base}/lib/jetty-continuation-TEST.jar +LIB|${jetty.base}/lib/jetty-http-TEST.jar +LIB|${jetty.base}/lib/jetty-io-TEST.jar +LIB|${jetty.base}/lib/jetty-deploy-TEST.jar +LIB|${jetty.base}/lib/jetty-jmx-TEST.jar +LIB|${jetty.base}/lib/jetty-jndi-TEST.jar +LIB|${jetty.base}/lib/jetty-plus-TEST.jar +LIB|${jetty.base}/lib/jetty-schemas-3.1.jar +LIB|${jetty.base}/lib/jetty-security-TEST.jar +LIB|${jetty.base}/lib/jetty-server-TEST.jar +LIB|${jetty.base}/lib/jetty-servlet-TEST.jar +LIB|${jetty.base}/lib/jetty-util-TEST.jar +LIB|${jetty.base}/lib/jetty-webapp-TEST.jar +LIB|${jetty.base}/lib/jetty-xml-TEST.jar +LIB|${jetty.base}/lib/spdy/spdy-client-TEST.jar +LIB|${jetty.base}/lib/spdy/spdy-core-TEST.jar +LIB|${jetty.base}/lib/spdy/spdy-http-common-TEST.jar +LIB|${jetty.base}/lib/spdy/spdy-http-server-TEST.jar +LIB|${jetty.base}/lib/spdy/spdy-server-TEST.jar +LIB|${jetty.base}/lib/jndi/javax.activation-1.1.jar +LIB|${jetty.base}/lib/jndi/javax.transaction-api-1.2.jar +LIB|${jetty.base}/lib/servlet-api-3.1.jar +LIB|${jetty.base}/lib/websocket/javax.websocket-api-1.0.jar +LIB|${jetty.base}/lib/websocket/javax-websocket-client-impl-TEST.jar +LIB|${jetty.base}/lib/websocket/javax-websocket-server-impl-TEST.jar +LIB|${jetty.base}/lib/websocket/websocket-api-TEST.jar +LIB|${jetty.base}/lib/websocket/websocket-client-TEST.jar +LIB|${jetty.base}/lib/websocket/websocket-common-TEST.jar +LIB|${jetty.base}/lib/websocket/websocket-server-TEST.jar +LIB|${jetty.base}/lib/websocket/websocket-servlet-TEST.jar + +# The Properties we expect (order is irrelevant) +PROP|jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g +PROP|jetty.keystore=etc/keystore +PROP|jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4 +PROP|jetty.secure.port=8443 +PROP|jetty.truststore=etc/keystore +PROP|jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4 +PROP|protonego=alpn +PROP|spdy.port=8443 +PROP|spdy.timeout=30000 + +# JVM Args +JVM|-Xms1024m +JVM|-Xmx1024m + +# Downloads +DOWNLOAD|http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar +DOWNLOAD|http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore + +# Files +FILE|lib/ +FILE|lib/alpn/ + + diff --git a/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt b/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt index b097f5d12f4..40577a7ed30 100644 --- a/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt +++ b/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt @@ -1,10 +1,12 @@ # The XMLs we expect (order is important) XML|${jetty.home}/etc/jetty-jmx.xml +XML|${jetty.home}/etc/protonego-alpn.xml XML|${jetty.home}/etc/jetty.xml XML|${jetty.home}/etc/jetty-http.xml XML|${jetty.home}/etc/jetty-ssl.xml XML|${jetty.home}/etc/jetty-spdy.xml + # The LIBs we expect (order is irrelevant) LIB|${jetty.home}/lib/jetty-continuation-TEST.jar LIB|${jetty.home}/lib/jetty-http-TEST.jar @@ -23,15 +25,25 @@ LIB|${jetty.home}/lib/spdy/spdy-core-TEST.jar # The Properties we expect (order is irrelevant) PROP|jetty.port=9090 +PROP|jetty.secure.port=8443 PROP|jetty.keystore=etc/keystore PROP|jetty.keystore.password=friendly PROP|jetty.keymanager.password=icecream PROP|jetty.truststore=etc/keystore PROP|jetty.truststore.password=sundae -PROP|java.version=1.7.0_21 +PROP|java.version=1.7.0_60 +PROP|protonego=alpn +PROP|spdy.port=8443 +PROP|spdy.timeout=30000 # The Downloads -DOWNLOAD|http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar +DOWNLOAD|http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar +DOWNLOAD|http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore # The Bootlib -BOOTLIB|-Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar +BOOTLIB|-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar + +# The Files +FILE|lib/ +FILE|lib/alpn/ + diff --git a/jetty-start/src/test/resources/usecases/home/etc/protonego-alpn.xml b/jetty-start/src/test/resources/usecases/home/etc/protonego-alpn.xml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jetty-start/src/test/resources/usecases/home/etc/protonego-npn.xml b/jetty-start/src/test/resources/usecases/home/etc/protonego-npn.xml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn.mod b/jetty-start/src/test/resources/usecases/home/modules/npn.mod deleted file mode 100644 index 9c9d4bcd1d3..00000000000 --- a/jetty-start/src/test/resources/usecases/home/modules/npn.mod +++ /dev/null @@ -1,4 +0,0 @@ - -[depend] -npn/npn-${java.version} - diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod new file mode 100644 index 00000000000..45bbad75c9f --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod new file mode 100644 index 00000000000..45bbad75c9f --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod new file mode 100644 index 00000000000..45bbad75c9f --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod new file mode 100644 index 00000000000..45bbad75c9f --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod new file mode 100644 index 00000000000..45bbad75c9f --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod new file mode 100644 index 00000000000..65e6cb3c4db --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.0.0.v20140317/alpn-boot-8.0.0.v20140317.jar|lib/alpn/alpn-boot-8.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.0.0.v20140317.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod new file mode 100644 index 00000000000..65e6cb3c4db --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.0.0.v20140317/alpn-boot-8.0.0.v20140317.jar|lib/alpn/alpn-boot-8.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.0.0.v20140317.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod new file mode 100644 index 00000000000..0e399f05cb1 --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod @@ -0,0 +1,36 @@ +# ALPN is provided via a -Xbootclasspath that modifies the secure connections +# in java to support the ALPN layer needed for SPDY (and eventually HTTP/2) +# +# This modification has a tight dependency on specific recent updates of +# Java 1.7 and Java 1.8 +# (Java versions prior to 1.7u40 are not supported) +# +# The alpn protonego module will use an appropriate alpn-boot jar for your +# specific version of Java. +# +# IMPORTANT: Versions of Java that exist after this module was created are +# not guaranteed to work with existing alpn-boot jars, and might +# need a new alpn-boot to be created / tested / deployed by the +# Jetty project in order to provide support for these future +# Java versions. +# +# All versions of alpn-boot can be found at +# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/ + +[name] +protonego-impl + +[depend] +protonego-impl/alpn-${java.version} + +[lib] +lib/jetty-alpn-client-${jetty.version}.jar +lib/jetty-alpn-server-${jetty.version}.jar + +[xml] +etc/protonego-alpn.xml + +[files] +lib/ +lib/alpn/ + diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_04.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_04.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod index a6778222464..007570b6757 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_04.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_05.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_05.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod index a6778222464..007570b6757 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_05.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_06.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_06.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod index bb6b64bf1f1..868a7a77fcb 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_06.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_07.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_07.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod index bb6b64bf1f1..868a7a77fcb 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_07.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_09.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_09.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod index c488457f14e..20c1db27bd5 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_09.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_10.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_10.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod index c488457f14e..20c1db27bd5 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_10.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_11.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_11.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod index c488457f14e..20c1db27bd5 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_11.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_13.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_13.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod index 0264d724869..1645a52dba0 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_13.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.4.v20130313/npn-boot-1.1.4.v20130313.jar|lib/npn/npn-boot-1.1.4.v20130313.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_15.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_15.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod index d2d09ea2d68..73bc09007eb 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_15.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_17.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_17.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod index d2d09ea2d68..73bc09007eb 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_17.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_21.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_21.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod index d2d09ea2d68..73bc09007eb 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_21.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_25.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_25.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod index d2d09ea2d68..73bc09007eb 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_25.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_40.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_40.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod index 909bebf5f70..465e6f034b6 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_40.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_45.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_45.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod index 909bebf5f70..465e6f034b6 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_45.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_51.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_51.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod index 909bebf5f70..465e6f034b6 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_51.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_55.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_55.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod index 6f6b4250803..639c70e3ffd 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_55.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_60.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod similarity index 93% rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_60.mod rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod index 6f6b4250803..639c70e3ffd 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_60.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod @@ -1,5 +1,5 @@ [name] -npn-boot +protonego-boot [files] http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod new file mode 100644 index 00000000000..040aad10197 --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod @@ -0,0 +1,31 @@ +# NPN is provided via a -Xbootclasspath that modifies the secure connections +# in java to support the NPN layer needed for SPDY. +# +# This modification has a tight dependency on specific updates of Java 1.7. +# (No support for Java 8 exists for npn / npn-boot, use alpn instead) +# +# The npn module will use an appropriate npn-boot jar for your specific +# version of Java. +# +# IMPORTANT: Versions of Java that exist after this module was created are +# not guaranteed to work with existing npn-boot jars, and might +# need a new npn-boot to be created / tested / deployed by the +# Jetty project in order to provide support for these future +# Java versions. +# +# All versions of npn-boot can be found at +# http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/ + + +[name] +protonego-impl + +[depend] +protonego-impl/npn-${java.version} + +[xml] +etc/protonego-npn.xml + +[files] +lib/ +lib/npn/ diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego.mod new file mode 100644 index 00000000000..d7bba9fbeca --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/protonego.mod @@ -0,0 +1,15 @@ +# +# Protocol Negotiatin Selection Module +# + +[depend] +protonego-impl/${protonego} + +[ini-template] +# Protocol Negotiation Implementation Selection +# choices are: +# 'npn' : original implementation for SPDY (now deprecated) +# 'alpn' : replacement for NPN, in use by current SPDY implementations +# and the future HTTP/2 spec +# Note: java 1.8+ are ALPN only. +protonego=alpn diff --git a/jetty-start/src/test/resources/usecases/home/modules/spdy.mod b/jetty-start/src/test/resources/usecases/home/modules/spdy.mod index 92e31a2b231..cf79dfa0f20 100644 --- a/jetty-start/src/test/resources/usecases/home/modules/spdy.mod +++ b/jetty-start/src/test/resources/usecases/home/modules/spdy.mod @@ -1,7 +1,10 @@ +# +# SPDY Support Module +# [depend] -server -npn +ssl +protonego [lib] lib/spdy/*.jar @@ -9,3 +12,15 @@ lib/spdy/*.jar [xml] etc/jetty-ssl.xml etc/jetty-spdy.xml + +[ini-template] +## SPDY Configuration + +# Port for SPDY connections +spdy.port=8443 + +# SPDY idle timeout in milliseconds +spdy.timeout=30000 + +# Initial Window Size for SPDY +#spdy.initialWindowSize=65536 diff --git a/jetty-start/src/test/resources/usecases/home/modules/ssl.mod b/jetty-start/src/test/resources/usecases/home/modules/ssl.mod new file mode 100644 index 00000000000..449f58104fb --- /dev/null +++ b/jetty-start/src/test/resources/usecases/home/modules/ssl.mod @@ -0,0 +1,35 @@ +# +# SSL Keystore module +# + +[depend] +server + +[xml] +etc/jetty-ssl.xml + +[files] +http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore + +[ini-template] +## SSL Keystore Configuration +# define the port to use for secure redirection +jetty.secure.port=8443 + +# Setup a demonstration keystore and truststore +jetty.keystore=etc/keystore +jetty.truststore=etc/keystore + +# Set the demonstration passwords. +# Note that OBF passwords are not secure, just protected from casual observation +# See http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html +jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4 +jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g +jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4 + +# Set the client auth behavior +# Set to true if client certificate authentication is required +# jetty.ssl.needClientAuth=true +# Set to true if client certificate authentication is desired +# jetty.ssl.wantClientAuth=true + From 72e0d800ac4297b663a64dc7d71eb350ac4f31da Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Sat, 21 Jun 2014 12:09:02 +0200 Subject: [PATCH 119/269] Made ALPN API dependency provided. --- jetty-http2/http2-server/pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index 0bf5ecc0cd7..df00ecba344 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -71,6 +71,12 @@ jetty-server ${project.version} + + org.eclipse.jetty.alpn + alpn-api + ${alpn.api.version} + provided + org.eclipse.jetty jetty-servlet @@ -83,12 +89,6 @@ ${project.version} test - - org.eclipse.jetty.alpn - alpn-api - ${alpn.api.version} - test - org.eclipse.jetty.toolchain jetty-test-helper From 86b0d7733803040f0b0a40c5864ca776c8872ef6 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Sat, 21 Jun 2014 12:10:13 +0200 Subject: [PATCH 120/269] Improved the server transport implementation, and fixed a case where the end stream flag was erroneously sent with more content to send. --- .../http2/server/HttpTransportOverHTTP2.java | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 9beebceb946..e9e8ad69b1e 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -39,6 +39,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport private static final Logger LOG = Log.getLogger(HttpTransportOverHTTP2.class); private final AtomicBoolean commit = new AtomicBoolean(); + private final Callback commitCallback = new CommitCallback(); private final IStream stream; private final HeadersFrame request; @@ -57,18 +58,12 @@ public class HttpTransportOverHTTP2 implements HttpTransport if (commit.compareAndSet(false, true)) { - commit(info, !hasContent, !hasContent ? callback : new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - // TODO - } - }); + boolean endStream = !hasContent && lastContent; + commit(info, endStream, !hasContent ? callback : commitCallback); } else { - // TODO + callback.failed(new IllegalStateException()); } if (hasContent) @@ -82,7 +77,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport if (LOG.isDebugEnabled()) { LOG.debug("HTTP2 Response #{}:{}{} {}{}{}", - stream.getId(), System.lineSeparator(), HttpVersion.HTTP_2, info.getStatus(), System.lineSeparator(), info.getHttpFields()); + stream.getId(), System.lineSeparator(), HttpVersion.HTTP_2, info.getStatus(), + System.lineSeparator(), info.getHttpFields()); } MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2, info.getStatus(), info.getHttpFields()); @@ -98,7 +94,6 @@ public class HttpTransportOverHTTP2 implements HttpTransport LOG.debug("HTTP2 Response #{}: {} content bytes{}", stream.getId(), content.remaining(), lastContent ? " (last chunk)" : ""); } - DataFrame frame = new DataFrame(stream.getId(), content, lastContent); stream.data(frame, callback); } @@ -111,5 +106,26 @@ public class HttpTransportOverHTTP2 implements HttpTransport @Override public void abort() { + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Response #{} aborted"); + stream.getSession().disconnect(); + } + + private class CommitCallback implements Callback + { + @Override + public void succeeded() + { + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Response #{} committed", stream.getId()); + } + + @Override + public void failed(Throwable x) + { + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Response #" + stream.getId() + " failed to commit", x); + stream.getSession().disconnect(); + } } } From f09b81835e9de1aa797853b5537e21cc5998f4fd Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 24 Jun 2014 10:22:49 +0200 Subject: [PATCH 121/269] Improved handling of RST_STREAM frames. --- .../jetty/http2/client/StreamResetTest.java | 182 ++++++++++++++++++ .../test/resources/jetty-logging.properties | 1 + .../org/eclipse/jetty/http2/HTTP2Session.java | 14 +- 3 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java new file mode 100644 index 00000000000..2bc87b45a08 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java @@ -0,0 +1,182 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.parser.ErrorCode; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FuturePromise; +import org.junit.Assert; +import org.junit.Test; + +public class StreamResetTest extends AbstractTest +{ + @Test + public void testStreamSendingResetIsRemoved() throws Exception + { + startServer(new ServerSessionListener.Adapter()); + + Session client = newClient(new Session.Listener.Adapter()); + MetaData.Request request = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, request, null, false); + FuturePromise promise = new FuturePromise<>(); + client.newStream(requestFrame, promise, new Stream.Listener.Adapter()); + Stream stream = promise.get(5, TimeUnit.SECONDS); + ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR); + stream.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); + // After reset the stream should be gone. + Assert.assertEquals(0, client.getStreams().size()); + } + + @Test + public void testStreamReceivingResetIsRemoved() throws Exception + { + final AtomicReference streamRef = new AtomicReference<>(); + final CountDownLatch resetLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public void onReset(Session session, ResetFrame frame) + { + Stream stream = session.getStream(frame.getStreamId()); + Assert.assertNotNull(stream); + Assert.assertTrue(stream.isReset()); + streamRef.set(stream); + resetLatch.countDown(); + } + }); + + Session client = newClient(new Session.Listener.Adapter()); + MetaData.Request request = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, request, null, false); + FuturePromise promise = new FuturePromise<>(); + client.newStream(requestFrame, promise, new Stream.Listener.Adapter()); + Stream stream = promise.get(5, TimeUnit.SECONDS); + ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR); + stream.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); + + Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); + Stream serverStream = streamRef.get(); + Assert.assertEquals(0, serverStream.getSession().getStreams().size()); + } + + @Test + public void testStreamResetDoesNotCloseConnection() throws Exception + { + final CountDownLatch serverResetLatch = new CountDownLatch(1); + final CountDownLatch serverDataLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) + { + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, false); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + return new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), Callback.Adapter.INSTANCE); + serverDataLatch.countDown(); + } + }; + } + + @Override + public void onReset(Session session, ResetFrame frame) + { + Stream stream = session.getStream(frame.getStreamId()); + // Simulate that there is pending data to send. + stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), new Callback.Adapter() + { + @Override + public void failed(Throwable x) + { + serverResetLatch.countDown(); + } + }); + } + }); + + Session client = newClient(new Session.Listener.Adapter()); + MetaData.Request request1 = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame1 = new HeadersFrame(0, request1, null, false); + FuturePromise promise1 = new FuturePromise<>(); + final CountDownLatch stream1HeadersLatch = new CountDownLatch(1); + final CountDownLatch stream1DataLatch = new CountDownLatch(1); + client.newStream(requestFrame1, promise1, new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + stream1HeadersLatch.countDown(); + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + stream1DataLatch.countDown(); + } + }); + Stream stream1 = promise1.get(5, TimeUnit.SECONDS); + Assert.assertTrue(stream1HeadersLatch.await(5, TimeUnit.SECONDS)); + + MetaData.Request request2 = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame2 = new HeadersFrame(0, request2, null, false); + FuturePromise promise2 = new FuturePromise<>(); + final CountDownLatch stream2DataLatch = new CountDownLatch(1); + client.newStream(requestFrame2, promise2, new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + stream2DataLatch.countDown(); + } + }); + Stream stream2 = promise2.get(5, TimeUnit.SECONDS); + + ResetFrame resetFrame = new ResetFrame(stream1.getId(), ErrorCode.CANCEL_STREAM_ERROR); + stream1.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); + + Assert.assertTrue(serverResetLatch.await(5, TimeUnit.SECONDS)); + // Stream MUST NOT receive data sent by server after reset. + Assert.assertFalse(stream1DataLatch.await(1, TimeUnit.SECONDS)); + + // The other stream should still be working. + stream2.data(new DataFrame(stream2.getId(), ByteBuffer.allocate(16), true), Callback.Adapter.INSTANCE); + Assert.assertTrue(serverDataLatch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(stream2DataLatch.await(5, TimeUnit.SECONDS)); + } +} diff --git a/jetty-http2/http2-client/src/test/resources/jetty-logging.properties b/jetty-http2/http2-client/src/test/resources/jetty-logging.properties index b4e43807801..251c25f4e5e 100644 --- a/jetty-http2/http2-client/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-client/src/test/resources/jetty-logging.properties @@ -1,2 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.http2.hpack.LEVEL=INFO org.eclipse.jetty.http2.LEVEL=INFO diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 3c4931907bb..93dbc6d6fe9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.http2; +import java.io.EOFException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.charset.StandardCharsets; @@ -319,14 +320,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener public void reset(ResetFrame frame, Callback callback) { if (closed.get()) - { callback.succeeded(); - } else - { - // TODO: think about moving reset() to Stream. control(getStream(frame.getStreamId()), frame, callback); - } } @Override @@ -677,8 +673,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener for (int i = 0; i < reset.size(); ++i) { FlusherEntry entry = reset.get(i); - // TODO: introduce a StreamResetException ? - entry.failed(new IllegalStateException()); + entry.reset(); } reset.clear(); @@ -783,6 +778,11 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } + public void reset() + { + callback.failed(new EOFException("reset")); + } + @Override public void succeeded() { From 8016fb6d0f66a66aec04095ffc0fb60c0ec64cf9 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 24 Jun 2014 10:49:52 +0200 Subject: [PATCH 122/269] Strengthened the checks to avoid to exceed the max frame length. --- .../jetty/http2/generator/GoAwayGenerator.java | 11 ++++++++++- .../jetty/http2/generator/PushPromiseGenerator.java | 9 ++++++--- .../jetty/http2/generator/SettingsGenerator.java | 8 +++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index 121059875f0..e88aa611659 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; +import java.util.Arrays; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.Frame; @@ -46,7 +47,15 @@ public class GoAwayGenerator extends FrameGenerator if (lastStreamId < 0) throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId); - int length = 4 + 4 + (payload != null ? payload.length : 0); + // The last streamId + the error code. + int fixedLength = 4 + 4; + + // Make sure we don't exceed the frame max length. + int maxPayloadLength = Frame.MAX_LENGTH - fixedLength; + if (payload != null && payload.length > maxPayloadLength) + payload = Arrays.copyOfRange(payload, 0, maxPayloadLength); + + int length = fixedLength + (payload != null ? payload.length : 0); ByteBuffer header = generateHeader(lease, FrameType.GO_AWAY, length, Flag.NONE, 0); header.putInt(lastStreamId); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index 4c7bcb60bb9..db074e682e9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -20,12 +20,12 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.hpack.HpackEncoder; -import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; @@ -55,12 +55,15 @@ public class PushPromiseGenerator extends FrameGenerator encoder.encode(metaData, lease); + // The promised streamId. + int fixedLength = 4; + long length = lease.getTotalLength(); - if (length > Frame.MAX_LENGTH) + if (length > Frame.MAX_LENGTH - fixedLength) throw new IllegalArgumentException("Invalid headers, too big"); // Space for the promised streamId. - length += 4; + length += fixedLength; int flags = Flag.END_HEADERS; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index 43971341750..87e5fbe95c7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -44,7 +44,13 @@ public class SettingsGenerator extends FrameGenerator public void generateSettings(ByteBufferPool.Lease lease, Map settings, boolean reply) { - ByteBuffer header = generateHeader(lease, FrameType.SETTINGS, 5 * settings.size(), reply ? Flag.ACK : Flag.NONE, 0); + // One byte for the identifier, 4 bytes for the value. + int entryLength = 1 + 4; + int length = entryLength * settings.size(); + if (length > Frame.MAX_LENGTH) + throw new IllegalArgumentException("Invalid settings, too big"); + + ByteBuffer header = generateHeader(lease, FrameType.SETTINGS, length, reply ? Flag.ACK : Flag.NONE, 0); for (Map.Entry entry : settings.entrySet()) { From 7625844dff7af2009a6207d8c67cc551dc220f7b Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 24 Jun 2014 10:53:21 +0200 Subject: [PATCH 123/269] Closing the connection if frames that carry headers don't have the END_HEADERS flag. --- .../eclipse/jetty/http2/parser/HeadersBodyParser.java | 8 ++++++++ .../jetty/http2/parser/PushPromiseBodyParser.java | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 1fd9a0a0393..e6f08b80955 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -78,7 +78,15 @@ public class HeadersBodyParser extends BodyParser { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); } + + // For now we don't support HEADERS frames that don't have END_HEADERS. + if (!hasFlag(Flag.END_HEADERS)) + { + return notifyConnectionFailure(ErrorCode.INTERNAL_ERROR, "unsupported_headers_frame"); + } + length = getBodyLength(); + if (isPaddingHigh()) { state = State.PADDING_HIGH; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java index dd0a7ae3715..ff81fd662f5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.PushPromiseFrame; public class PushPromiseBodyParser extends BodyParser @@ -62,7 +63,15 @@ public class PushPromiseBodyParser extends BodyParser { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); } + + // For now we don't support PUSH_PROMISE frames that don't have END_HEADERS. + if (!hasFlag(Flag.END_HEADERS)) + { + return notifyConnectionFailure(ErrorCode.INTERNAL_ERROR, "unsupported_push_promise_frame"); + } + length = getBodyLength(); + if (isPaddingHigh()) { state = State.PADDING_HIGH; From e94b8745f20a2e5eb6c0178e208d495b1c1c5dcd Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 24 Jun 2014 12:34:35 +0200 Subject: [PATCH 124/269] PING frames are now processed as soon as possible. --- .../main/java/org/eclipse/jetty/http2/HTTP2Session.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 93dbc6d6fe9..5d3c986537b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -39,6 +39,7 @@ import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; @@ -356,7 +357,11 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { if (LOG.isDebugEnabled()) LOG.debug("Sending {}", entry.frame); - flusher.append(entry); + // Ping frames are prepended to process them as soon as possible. + if (entry.frame.getType() == FrameType.PING) + flusher.prepend(entry); + else + flusher.append(entry); flusher.iterate(); } From 05616d1e9d387a91db59ee74a57a40fe38443a79 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 24 Jun 2014 13:50:52 +0200 Subject: [PATCH 125/269] Cosmetics. --- .../main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index a57bce3ff3b..9111a1f17ad 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -75,6 +75,7 @@ public class HTTP2FlowControl implements FlowControl int delta = frame.getWindowDelta(); if (frame.getStreamId() > 0) { + // The stream may have been reset concurrently. if (stream != null) { int oldSize = stream.updateWindowSize(delta); @@ -84,7 +85,7 @@ public class HTTP2FlowControl implements FlowControl } else { - int oldSize = session.updateWindowSize(frame.getWindowDelta()); + int oldSize = session.updateWindowSize(delta); if (LOG.isDebugEnabled()) LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize + delta, session); } From 02454ec8dee472ac523bac91320d037a422d127e Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 24 Jun 2014 13:52:03 +0200 Subject: [PATCH 126/269] Improved handling of errors for streams. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 2 ++ .../org/eclipse/jetty/http2/HTTP2Stream.java | 28 ++++++++++--------- .../java/org/eclipse/jetty/http2/IStream.java | 2 ++ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 5d3c986537b..e8acbcc2777 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -815,6 +815,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void failed(Throwable x) { + if (stream != null) + stream.close(); close(ErrorCode.INTERNAL_ERROR, "generator_error", Adapter.INSTANCE); callback.failed(x); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 9da557c4a4e..bfa321c4090 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -54,7 +54,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream private final ISession session; private final HeadersFrame frame; private volatile Listener listener; - private volatile boolean reset = false; + private volatile boolean reset; public HTTP2Stream(Scheduler scheduler, ISession session, HeadersFrame frame) { @@ -131,8 +131,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream // The stream is now gone, we must close it to // avoid that its idle timeout is rescheduled. - closeState.set(CloseState.CLOSED); - onClose(); + close(); session.reset(new ResetFrame(getId(), ErrorCode.CANCEL_STREAM_ERROR), disconnectOnFailure); @@ -220,19 +219,15 @@ public class HTTP2Stream extends IdleTimeout implements IStream } case LOCALLY_CLOSED: { - if (local) - return; - if (closeState.compareAndSet(current, CloseState.CLOSED)) - return; - break; + if (!local) + close(); + return; } case REMOTELY_CLOSED: { - if (!local) - return; - if (closeState.compareAndSet(current, CloseState.CLOSED)) - return; - break; + if (local) + close(); + return; } default: { @@ -254,6 +249,13 @@ public class HTTP2Stream extends IdleTimeout implements IStream return windowSize.getAndAdd(delta); } + @Override + public void close() + { + closeState.set(CloseState.CLOSED); + onClose(); + } + protected void notifyData(Stream stream, DataFrame frame, Callback callback) { final Listener listener = this.listener; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 5bd23056bb6..fa709c4f48f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -47,4 +47,6 @@ public interface IStream extends Stream public int getWindowSize(); public int updateWindowSize(int delta); + + public void close(); } From 4c2c7e8352886cb6ed189fe5715c71f0a21e3158 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 25 Jun 2014 12:37:05 +0200 Subject: [PATCH 127/269] Guarded calls to LOG.debug() with if (LOG.isDebugEnabled()) to reduce allocation of varargs Object[]. --- .../main/java/org/eclipse/jetty/http2/HTTP2Session.java | 3 ++- .../java/org/eclipse/jetty/http2/hpack/HpackDecoder.java | 9 ++++++--- .../java/org/eclipse/jetty/http2/hpack/HpackEncoder.java | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index e8acbcc2777..c2377b365b2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -226,7 +226,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (LOG.isDebugEnabled()) { String reason = tryConvertPayload(frame.getPayload()); - LOG.debug("Received {}: {}/'{}'", frame.getType(), frame.getError(), reason); + if (LOG.isDebugEnabled()) + LOG.debug("Received {}: {}/'{}'", frame.getType(), frame.getError(), reason); } flusher.close(); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 136bb8541d3..82efe316c36 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -87,7 +87,8 @@ public class HpackDecoder _context.get(index).removeFromRefSet(); else if (entry.isStatic()) { - LOG.debug("decode IdxStatic {}",entry); + if (LOG.isDebugEnabled()) + LOG.debug("decode IdxStatic {}",entry); // emit field _builder.emit(entry.getHttpField()); @@ -98,7 +99,8 @@ public class HpackDecoder } else { - LOG.debug("decode Idx {}",entry); + if (LOG.isDebugEnabled()) + LOG.debug("decode Idx {}",entry); // emit _builder.emit(entry.getHttpField()); // add to reference set @@ -227,7 +229,8 @@ public class HpackDecoder else if (f==3) { // clear reference set - LOG.debug("decode clear"); + if (LOG.isDebugEnabled()) + LOG.debug("decode clear"); _context.clearReferenceSet(); } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 1ba7ae3adf0..445e55370b6 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -345,7 +345,8 @@ public class HpackEncoder if (p>=0) { int e=buffer.position(); - LOG.debug("encoded '{}' by {} to '{}'",field,encoding,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); + if (LOG.isDebugEnabled()) + LOG.debug("encoded '{}' by {} to '{}'",field,encoding,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); } } } From 9f844383cdb528d67ec69895dd8c6117b6e36e13 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Wed, 25 Jun 2014 14:11:44 -0700 Subject: [PATCH 128/269] Making PathResource the default for "file://" resources + Making ResourceTest a proper @Parameterized test case + Moving jar tests out of ResourceTest into JarResourceTest + Moving classpath tests out of ResourceTest into ClassPathResourceTest + Making more improvements to PathResource to satisfy expecations in the rest of the codebase. + Requests for resource subpaths that use "//" in their strings will now work correctly (it used to result in null requests in FileResource) --- .../internal/DefaultFileLocatorHelper.java | 5 +- .../jetty/server/handler/ResourceHandler.java | 6 +- .../ContextHandlerGetResourceTest.java | 23 +- .../jetty/util/resource/FileResource.java | 2 + .../jetty/util/resource/JarFileResource.java | 2 +- .../jetty/util/resource/PathResource.java | 43 +- .../eclipse/jetty/util/resource/Resource.java | 7 +- .../util/resource/AbstractFSResourceTest.java | 14 + .../util/resource/ClassPathResourceTest.java | 108 ++++ .../jetty/util/resource/JarResourceTest.java | 203 +++++++ .../jetty/util/resource/ResourceTest.java | 558 +++++------------- 11 files changed, 546 insertions(+), 425 deletions(-) create mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/resource/ClassPathResourceTest.java create mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/resource/JarResourceTest.java diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java index fed6f8b6cf4..35eb00b697f 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java @@ -33,6 +33,7 @@ import java.util.zip.ZipFile; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.resource.FileResource; +import org.eclipse.jetty.util.resource.PathResource; import org.eclipse.jetty.util.resource.Resource; import org.osgi.framework.Bundle; @@ -100,10 +101,10 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper if (url.getProtocol().equals("file")) { - // some osgi frameworks do use the file protocole directly in some + // some osgi frameworks do use the file protocol directly in some // situations. Do use the FileResource to transform the URL into a // File: URL#toURI is broken - return new FileResource(url).getFile().getParentFile().getParentFile(); + return new PathResource(url).getFile().getParentFile().getParentFile(); } else if (url.getProtocol().equals("bundleentry")) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java index 8cbebbdbb52..1db4283bc64 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java @@ -45,7 +45,7 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.FileResource; +import org.eclipse.jetty.util.resource.PathResource; import org.eclipse.jetty.util.resource.Resource; @@ -523,7 +523,7 @@ public class ResourceHandler extends HandlerWrapper // Can we use a memory mapped file? if (_minMemoryMappedContentLength>0 && resource.length()>_minMemoryMappedContentLength && - resource instanceof FileResource) + resource instanceof PathResource) { ByteBuffer buffer = BufferUtil.toMappedBuffer(resource.getFile()); ((HttpOutput)out).sendContent(buffer,callback); @@ -543,7 +543,7 @@ public class ResourceHandler extends HandlerWrapper // Can we use a memory mapped file? if (_minMemoryMappedContentLength>0 && resource.length()>_minMemoryMappedContentLength && - resource instanceof FileResource) + resource instanceof PathResource) { ByteBuffer buffer = BufferUtil.toMappedBuffer(resource.getFile()); ((HttpOutput)out).sendContent(buffer); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java index 3ba83f6ed9d..1f5cddd74e1 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java @@ -18,12 +18,8 @@ package org.eclipse.jetty.server.handler; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import java.io.File; import java.net.MalformedURLException; @@ -122,7 +118,7 @@ public class ContextHandlerGetResourceTest try { context.getResource(path); - fail(); + fail("Expected " + MalformedURLException.class); } catch(MalformedURLException e) { @@ -131,7 +127,7 @@ public class ContextHandlerGetResourceTest try { context.getServletContext().getResource(path); - fail(); + fail("Expected " + MalformedURLException.class); } catch(MalformedURLException e) { @@ -300,17 +296,20 @@ public class ContextHandlerGetResourceTest @Test public void testSlashSlash() throws Exception { + File expected = new File(docroot, OS.separators("subdir/data.txt")); + URL expectedUrl = expected.toURI().toURL(); + String path="//subdir/data.txt"; Resource resource=context.getResource(path); - assertNull(resource); + assertThat("Resource: " + resource, resource.getFile(), is(expected)); URL url=context.getServletContext().getResource(path); - assertNull(url); + assertThat("Resource: " + url, url, is(expectedUrl)); path="/subdir//data.txt"; resource=context.getResource(path); - assertNull(resource); + assertThat("Resource: " + resource, resource.getFile(), is(expected)); url=context.getServletContext().getResource(path); - assertNull(url); + assertThat("Resource: " + url, url, is(expectedUrl)); } @Test diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java index 47776f4643a..412ffb94e93 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java @@ -46,7 +46,9 @@ import org.eclipse.jetty.util.log.Logger; * insensitivity). By default this is turned on, or it can be controlled * by calling the static method @see FileResource#setCheckAliases(boolean) * + * @deprecated use {@link PathResource} instead */ +@Deprecated public class FileResource extends Resource { private static final Logger LOG = Log.getLogger(FileResource.class); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java index 9d3b932b665..007d29f3fa4 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java @@ -269,7 +269,7 @@ class JarFileResource extends JarResource //So, do one retry to drop a connection and get a fresh JarFile LOG.warn("Retrying list:"+e); LOG.debug(e); - release(); + close(); list = listEntries(); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java index 824e5c59fee..5702052fd8d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java @@ -33,12 +33,13 @@ import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.LinkOption; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -105,9 +106,24 @@ public class PathResource extends Resource } @Override - public Resource addPath(String apath) throws IOException, MalformedURLException + public Resource addPath(final String subpath) throws IOException, MalformedURLException { - return new PathResource(this.path.resolve(apath)); + String cpath = URIUtil.canonicalPath(subpath); + + if ((cpath == null)||(cpath.length()==0)) + throw new MalformedURLException(); + + if ("/".equals(cpath)) + return this; + + // subpaths are always under PathResource + // compensate for input subpaths like "/subdir" + // where default java.nio.file behavior would be + // to treat that like an absolute path + StringBuilder relpath = new StringBuilder(); + relpath.append(".").append(File.separator); + relpath.append(cpath); + return new PathResource(this.path.resolve(relpath.toString()).normalize()); } @Override @@ -325,7 +341,7 @@ public class PathResource extends Resource PathResource destRes = (PathResource)dest; try { - Path result = Files.move(path,destRes.path,StandardCopyOption.ATOMIC_MOVE); + Path result = Files.move(path,destRes.path); return Files.exists(result,linkOptions); } catch (IOException e) @@ -340,6 +356,19 @@ public class PathResource extends Resource } } + @Override + public void copyTo(File destination) throws IOException + { + if (isDirectory()) + { + IO.copyDir(this.path.toFile(),destination); + } + else + { + Files.copy(this.path,destination.toPath()); + } + } + public void setFollowLinks(boolean followLinks) { if (followLinks) @@ -351,4 +380,10 @@ public class PathResource extends Resource linkOptions = new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; } } + + @Override + public String toString() + { + return this.uri.toASCIIString(); + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java index 181ccf0d2af..c77c9a649ca 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java @@ -113,8 +113,7 @@ public abstract class Resource implements ResourceFactory, Closeable { try { - FileResource fileResource= new FileResource(url); - return fileResource; + return new PathResource(url); } catch(Exception e) { @@ -178,7 +177,7 @@ public abstract class Resource implements ResourceFactory, Closeable resource=resource.substring(2); File file=new File(resource).getCanonicalFile(); - return new FileResource(file); + return new PathResource(file.toPath()); } catch(Exception e2) { @@ -199,7 +198,7 @@ public abstract class Resource implements ResourceFactory, Closeable /* ------------------------------------------------------------ */ public static Resource newResource(File file) { - return new FileResource(file); + return new PathResource(file.toPath()); } /* ------------------------------------------------------------ */ diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java index 62ef4f0e429..6761824d1d7 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java @@ -491,4 +491,18 @@ public abstract class AbstractFSResourceTest // Expected path } } + + @Test + public void testEncoding() throws Exception + { + File specials = testdir.getFile("a file with,spe#ials"); + try(Resource res= newResource(specials)) + { + assertThat("Specials URL", res.getURI().toASCIIString(), containsString("a%20file%20with,spe%23ials")); + assertThat("Specials Filename", res.getFile().toString(), containsString("a file with,spe#ials")); + + res.delete(); + assertThat("File should have been deleted.",res.exists(),is(false)); + } + } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ClassPathResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ClassPathResourceTest.java new file mode 100644 index 00000000000..df1da5e843a --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ClassPathResourceTest.java @@ -0,0 +1,108 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util.resource; + +import static org.junit.Assert.*; + +import java.io.File; + +import org.junit.Test; + +public class ClassPathResourceTest +{ + /** + * Test a class path resource for existence. + */ + @Test + public void testClassPathResourceClassRelative() + { + final String classPathName="Resource.class"; + + try(Resource resource=Resource.newClassPathResource(classPathName);) + { + // A class path cannot be a directory + assertFalse("Class path cannot be a directory.",resource.isDirectory()); + + // A class path must exist + assertTrue("Class path resource does not exist.",resource.exists()); + } + } + + /** + * Test a class path resource for existence. + */ + @Test + public void testClassPathResourceClassAbsolute() + { + final String classPathName="/org/eclipse/jetty/util/resource/Resource.class"; + + Resource resource=Resource.newClassPathResource(classPathName); + + // A class path cannot be a directory + assertFalse("Class path cannot be a directory.",resource.isDirectory()); + + // A class path must exist + assertTrue("Class path resource does not exist.",resource.exists()); + } + + /** + * Test a class path resource for directories. + */ + @Test + public void testClassPathResourceDirectory() throws Exception + { + final String classPathName="/"; + + Resource resource=Resource.newClassPathResource(classPathName); + + // A class path must be a directory + assertTrue("Class path must be a directory.",resource.isDirectory()); + + assertTrue("Class path returned file must be a directory.",resource.getFile().isDirectory()); + + // A class path must exist + assertTrue("Class path resource does not exist.",resource.exists()); + } + + /** + * Test a class path resource for a file. + */ + @Test + public void testClassPathResourceFile() throws Exception + { + final String fileName="resource.txt"; + final String classPathName="/"+fileName; + + // Will locate a resource in the class path + Resource resource=Resource.newClassPathResource(classPathName); + + // A class path cannot be a directory + assertFalse("Class path must be a directory.",resource.isDirectory()); + + assertTrue(resource!=null); + + File file=resource.getFile(); + + assertEquals("File name from class path is not equal.",fileName,file.getName()); + assertTrue("File returned from class path should be a file.",file.isFile()); + + // A class path must exist + assertTrue("Class path resource does not exist.",resource.exists()); + } +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/JarResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/JarResourceTest.java new file mode 100644 index 00000000000..e8d80f56fc5 --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/JarResourceTest.java @@ -0,0 +1,203 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util.resource; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.zip.ZipFile; + +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.IO; +import org.junit.Test; + +public class JarResourceTest +{ + private String testResURI = MavenTestingUtils.getTestResourcesDir().getAbsoluteFile().toURI().toASCIIString(); + + @Test + public void testJarFile() + throws Exception + { + String s = "jar:"+testResURI+"TestData/test.zip!/subdir/"; + Resource r = Resource.newResource(s); + + Set entries = new HashSet<>(Arrays.asList(r.list())); + assertEquals(3,entries.size()); + assertTrue(entries.contains("alphabet")); + assertTrue(entries.contains("numbers")); + assertTrue(entries.contains("subsubdir/")); + + File extract = File.createTempFile("extract", null); + if (extract.exists()) + extract.delete(); + extract.mkdir(); + extract.deleteOnExit(); + + r.copyTo(extract); + + Resource e = Resource.newResource(extract.getAbsolutePath()); + + entries = new HashSet<>(Arrays.asList(e.list())); + assertEquals(3,entries.size()); + assertTrue(entries.contains("alphabet")); + assertTrue(entries.contains("numbers")); + assertTrue(entries.contains("subsubdir/")); + IO.delete(extract); + + s = "jar:"+testResURI+"TestData/test.zip!/subdir/subsubdir/"; + r = Resource.newResource(s); + + entries = new HashSet<>(Arrays.asList(r.list())); + assertEquals(2,entries.size()); + assertTrue(entries.contains("alphabet")); + assertTrue(entries.contains("numbers")); + + extract = File.createTempFile("extract", null); + if (extract.exists()) + extract.delete(); + extract.mkdir(); + extract.deleteOnExit(); + + r.copyTo(extract); + + e = Resource.newResource(extract.getAbsolutePath()); + + entries = new HashSet<>(Arrays.asList(e.list())); + assertEquals(2,entries.size()); + assertTrue(entries.contains("alphabet")); + assertTrue(entries.contains("numbers")); + IO.delete(extract); + + } + + /* ------------------------------------------------------------ */ + @Test + public void testJarFileGetAllResoures() + throws Exception + { + String s = "jar:"+testResURI+"TestData/test.zip!/subdir/"; + Resource r = Resource.newResource(s); + Collection deep=r.getAllResources(); + + assertEquals(4, deep.size()); + } + + @Test + public void testJarFileIsContainedIn () + throws Exception + { + String s = "jar:"+testResURI+"TestData/test.zip!/subdir/"; + Resource r = Resource.newResource(s); + Resource container = Resource.newResource(testResURI+"TestData/test.zip"); + + assertTrue(r instanceof JarFileResource); + JarFileResource jarFileResource = (JarFileResource)r; + + assertTrue(jarFileResource.isContainedIn(container)); + + container = Resource.newResource(testResURI+"TestData"); + assertFalse(jarFileResource.isContainedIn(container)); + } + + /* ------------------------------------------------------------ */ + @Test + public void testJarFileLastModified () + throws Exception + { + String s = "jar:"+testResURI+"TestData/test.zip!/subdir/numbers"; + + try(ZipFile zf = new ZipFile(MavenTestingUtils.getTestResourceFile("TestData/test.zip"))) + { + long last = zf.getEntry("subdir/numbers").getTime(); + + Resource r = Resource.newResource(s); + assertEquals(last,r.lastModified()); + } + } + + /* ------------------------------------------------------------ */ + @Test + public void testJarFileCopyToDirectoryTraversal () throws Exception + { + String s = "jar:"+testResURI+"TestData/extract.zip!/"; + Resource r = Resource.newResource(s); + + assertTrue(r instanceof JarResource); + JarResource jarResource = (JarResource)r; + + File destParent = File.createTempFile("copyjar", null); + if (destParent.exists()) + destParent.delete(); + destParent.mkdir(); + destParent.deleteOnExit(); + + File dest = new File(destParent.getCanonicalPath()+"/extract"); + if(dest.exists()) + dest.delete(); + dest.mkdir(); + dest.deleteOnExit(); + + jarResource.copyTo(dest); + + // dest contains only the valid entry; dest.getParent() contains only the dest directory + assertEquals(1, dest.listFiles().length); + assertEquals(1, dest.getParentFile().listFiles().length); + + FilenameFilter dotdotFilenameFilter = new FilenameFilter() { + @Override + public boolean accept(File directory, String name) + { + return name.equals("dotdot.txt"); + } + }; + assertEquals(0, dest.listFiles(dotdotFilenameFilter).length); + assertEquals(0, dest.getParentFile().listFiles(dotdotFilenameFilter).length); + + FilenameFilter extractfileFilenameFilter = new FilenameFilter() { + @Override + public boolean accept(File directory, String name) + { + return name.equals("extract-filenotdir"); + } + }; + assertEquals(0, dest.listFiles(extractfileFilenameFilter).length); + assertEquals(0, dest.getParentFile().listFiles(extractfileFilenameFilter).length); + + FilenameFilter currentDirectoryFilenameFilter = new FilenameFilter() { + @Override + public boolean accept(File directory, String name) + { + return name.equals("current.txt"); + } + }; + assertEquals(1, dest.listFiles(currentDirectoryFilenameFilter).length); + assertEquals(0, dest.getParentFile().listFiles(currentDirectoryFilenameFilter).length); + + IO.delete(dest); + assertFalse(dest.exists()); + } + + +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java index 852a06b2933..5d53c939176 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java @@ -18,37 +18,30 @@ package org.eclipse.jetty.util.resource; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.junit.Assume.*; import java.io.File; -import java.io.FilePermission; -import java.io.FilenameFilter; import java.io.InputStream; import java.net.URI; import java.net.URL; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.zip.ZipFile; +import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.util.IO; -import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; - +@RunWith(Parameterized.class) public class ResourceTest { - public static String __userDir = System.getProperty("basedir", "."); - public static URL __userURL=null; - private static String __relDir=""; - private static File tmpFile; - private static final boolean DIR=true; private static final boolean EXISTS=true; @@ -96,6 +89,24 @@ public class ResourceTest this.dir=dir; resource=Resource.newResource(url); } + + Data(URI uri,boolean exists, boolean dir) + throws Exception + { + this.test=uri.toASCIIString(); + this.exists=exists; + this.dir=dir; + resource=Resource.newResource(uri); + } + + Data(File file,boolean exists, boolean dir) + throws Exception + { + this.test=file.toString(); + this.exists=exists; + this.dir=dir; + resource=Resource.newResource(file); + } Data(String url,boolean exists, boolean dir, String content) throws Exception @@ -106,408 +117,157 @@ public class ResourceTest this.content=content; resource=Resource.newResource(url); } + + @Override + public String toString() + { + return this.test; + } } - - public static Data[] data; - - /* ------------------------------------------------------------ */ - @BeforeClass - public static void setUp() - throws Exception + + static class UseCases { - if (data!=null) - return; - - File file = new File(__userDir); - file=new File(file.getCanonicalPath()); - URI uri = file.toURI(); - __userURL=uri.toURL(); + final Collection data; + final File fileRef; + final URI uriRef; + final String relRef; - __userURL = MavenTestingUtils.getTestResourcesDir().toURI().toURL(); - FilePermission perm = (FilePermission) __userURL.openConnection().getPermission(); - __userDir = new File(perm.getName()).getCanonicalPath() + File.separatorChar; - __relDir = "src/test/resources/".replace('/', File.separatorChar); + final Data[] baseCases; - //System.err.println("User Dir="+__userDir); - //System.err.println("Rel Dir="+__relDir); - //System.err.println("User URL="+__userURL); - - tmpFile=File.createTempFile("test",null).getCanonicalFile(); - tmpFile.deleteOnExit(); - - data = new Data[50]; - int i=0; - - data[i++]=new Data(tmpFile.toString(),EXISTS,!DIR); - - int rt=i; - data[i++]=new Data(__userURL,EXISTS,DIR); - data[i++]=new Data(__userDir,EXISTS,DIR); - data[i++]=new Data(__relDir,EXISTS,DIR); - data[i++]=new Data(__userURL+"resource.txt",EXISTS,!DIR); - data[i++]=new Data(__userDir+"resource.txt",EXISTS,!DIR); - data[i++]=new Data(__relDir+"resource.txt",EXISTS,!DIR); - data[i++]=new Data(__userURL+"NoName.txt",!EXISTS,!DIR); - data[i++]=new Data(__userDir+"NoName.txt",!EXISTS,!DIR); - data[i++]=new Data(__relDir+"NoName.txt",!EXISTS,!DIR); - - data[i++]=new Data(data[rt],"resource.txt",EXISTS,!DIR); - data[i++]=new Data(data[rt],"/resource.txt",EXISTS,!DIR); - data[i++]=new Data(data[rt],"NoName.txt",!EXISTS,!DIR); - data[i++]=new Data(data[rt],"/NoName.txt",!EXISTS,!DIR); - - int td=i; - data[i++]=new Data(data[rt],"TestData",EXISTS,DIR); - data[i++]=new Data(data[rt],"TestData/",EXISTS,DIR); - data[i++]=new Data(data[td],"alphabet.txt",EXISTS,!DIR,"ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - - data[i++]=new Data("jar:file:/somejar.jar!/content/",!EXISTS,DIR); - data[i++]=new Data("jar:file:/somejar.jar!/",!EXISTS,DIR); - - int tj=i; - data[i++]=new Data("jar:"+__userURL+"TestData/test.zip!/",EXISTS,DIR); - data[i++]=new Data(data[tj],"Unkown",!EXISTS,!DIR); - data[i++]=new Data(data[tj],"/Unkown/",!EXISTS,DIR); - - data[i++]=new Data(data[tj],"subdir",EXISTS,DIR); - data[i++]=new Data(data[tj],"/subdir/",EXISTS,DIR); - data[i++]=new Data(data[tj],"alphabet",EXISTS,!DIR, - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - data[i++]=new Data(data[tj],"/subdir/alphabet",EXISTS,!DIR, - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - - Resource base = Resource.newResource(__userDir); - Resource dir0 = base.addPath("TestData"); - assertTrue(dir0.isDirectory()); - assertTrue(dir0.toString().endsWith("/")); - assertTrue(dir0.getAlias()==null); - Resource dir1 = base.addPath("TestData/"); - assertTrue(dir1.isDirectory()); - assertTrue(dir1.toString().endsWith("/")); - assertTrue(dir1.getAlias()==null); - - + public UseCases(String ref) throws Exception { + this.data = new ArrayList(); + // relative directory reference + this.relRef = OS.separators(ref); + // File object reference + this.fileRef = MavenTestingUtils.getProjectDir(relRef); + // URI reference + this.uriRef = fileRef.toURI(); + + // create baseline cases + baseCases = new Data[] { + new Data(relRef,EXISTS,DIR), + new Data(uriRef,EXISTS,DIR), + new Data(fileRef,EXISTS,DIR) + }; + + // add all baseline cases + for (Data bcase : baseCases) + { + addCase(bcase); + } + } + + public void addCase(Data ucase) + { + this.data.add(new Data[]{ ucase }); + } + + public void addAllSimpleCases(String subpath, boolean exists, boolean dir) + throws Exception + { + addCase(new Data(OS.separators(relRef + subpath), exists, dir)); + addCase(new Data(uriRef.resolve(subpath).toURL(), exists, dir)); + addCase(new Data(new File(fileRef,subpath),exists, dir)); + } + + public Data addAllAddPathCases(String subpath, boolean exists, boolean dir) throws Exception + { + Data bdata = null; + + for (Data bcase : baseCases) + { + bdata = new Data(bcase, subpath, exists, dir); + addCase(bdata); + } + + return bdata; + } } - /* ------------------------------------------------------------ */ + @Parameters(name="{0}") + public static Collection data() throws Exception + { + UseCases cases = new UseCases("src/test/resources/"); + + File testDir = MavenTestingUtils.getTargetTestingDir(ResourceTest.class.getName()); + FS.ensureEmpty(testDir); + File tmpFile = File.createTempFile("test",null,testDir); + + cases.addCase(new Data(tmpFile.toString(),EXISTS,!DIR)); + + // Some resource references. + cases.addAllSimpleCases("resource.txt",EXISTS,!DIR); + cases.addAllSimpleCases("NoName.txt",!EXISTS,!DIR); + + // Some addPath() forms + cases.addAllAddPathCases("resource.txt",EXISTS,!DIR); + cases.addAllAddPathCases("/resource.txt",EXISTS,!DIR); + cases.addAllAddPathCases("//resource.txt",EXISTS,!DIR); + cases.addAllAddPathCases("NoName.txt",!EXISTS,!DIR); + cases.addAllAddPathCases("/NoName.txt",!EXISTS,!DIR); + cases.addAllAddPathCases("//NoName.txt",!EXISTS,!DIR); + + Data tdata1 = cases.addAllAddPathCases("TestData", EXISTS, DIR); + Data tdata2 = cases.addAllAddPathCases("TestData/", EXISTS, DIR); + + cases.addCase(new Data(tdata1, "alphabet.txt", EXISTS,!DIR,"ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + cases.addCase(new Data(tdata2, "alphabet.txt", EXISTS,!DIR,"ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + + cases.addCase(new Data("jar:file:/somejar.jar!/content/",!EXISTS,DIR)); + cases.addCase(new Data("jar:file:/somejar.jar!/",!EXISTS,DIR)); + + String urlRef = cases.uriRef.toASCIIString(); + Data zdata = new Data("jar:"+urlRef +"TestData/test.zip!/",EXISTS,DIR); + cases.addCase(zdata); + cases.addCase(new Data(zdata,"Unkown",!EXISTS,!DIR)); + cases.addCase(new Data(zdata,"/Unkown/",!EXISTS,DIR)); + + cases.addCase(new Data(zdata,"subdir",EXISTS,DIR)); + cases.addCase(new Data(zdata,"/subdir/",EXISTS,DIR)); + cases.addCase(new Data(zdata,"alphabet",EXISTS,!DIR, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + cases.addCase(new Data(zdata,"/subdir/alphabet",EXISTS,!DIR, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + + cases.addAllAddPathCases("/TestData/test/subdir/subsubdir/",EXISTS,DIR); + cases.addAllAddPathCases("//TestData/test/subdir/subsubdir/",EXISTS,DIR); + cases.addAllAddPathCases("/TestData//test/subdir/subsubdir/",EXISTS,DIR); + cases.addAllAddPathCases("/TestData/test//subdir/subsubdir/",EXISTS,DIR); + cases.addAllAddPathCases("/TestData/test/subdir//subsubdir/",EXISTS,DIR); + + cases.addAllAddPathCases("TestData/test/subdir/subsubdir/",EXISTS,DIR); + cases.addAllAddPathCases("TestData/test/subdir/subsubdir//",EXISTS,DIR); + cases.addAllAddPathCases("TestData/test/subdir//subsubdir/",EXISTS,DIR); + cases.addAllAddPathCases("TestData/test//subdir/subsubdir/",EXISTS,DIR); + + cases.addAllAddPathCases("/TestData/../TestData/test/subdir/subsubdir/",EXISTS,DIR); + + return cases.data; + } + + @Parameter(value=0) + public Data data; + @Test public void testResourceExists() { - for (int i=0;i0); - assertTrue(r.getFile().toString().indexOf("a file with,spe#ials")>0); - r.delete(); - assertFalse("File should have been deleted.",r.exists()); - } - - /* ------------------------------------------------------------ */ - @Test - public void testJarFile() - throws Exception - { - String s = "jar:"+__userURL+"TestData/test.zip!/subdir/"; - Resource r = Resource.newResource(s); - - Set entries = new HashSet<>(Arrays.asList(r.list())); - assertEquals(3,entries.size()); - assertTrue(entries.contains("alphabet")); - assertTrue(entries.contains("numbers")); - assertTrue(entries.contains("subsubdir/")); - - File extract = File.createTempFile("extract", null); - if (extract.exists()) - extract.delete(); - extract.mkdir(); - extract.deleteOnExit(); - - r.copyTo(extract); - - Resource e = Resource.newResource(extract.getAbsolutePath()); - - entries = new HashSet<>(Arrays.asList(e.list())); - assertEquals(3,entries.size()); - assertTrue(entries.contains("alphabet")); - assertTrue(entries.contains("numbers")); - assertTrue(entries.contains("subsubdir/")); - IO.delete(extract); - - s = "jar:"+__userURL+"TestData/test.zip!/subdir/subsubdir/"; - r = Resource.newResource(s); - - entries = new HashSet<>(Arrays.asList(r.list())); - assertEquals(2,entries.size()); - assertTrue(entries.contains("alphabet")); - assertTrue(entries.contains("numbers")); - - extract = File.createTempFile("extract", null); - if (extract.exists()) - extract.delete(); - extract.mkdir(); - extract.deleteOnExit(); - - r.copyTo(extract); - - e = Resource.newResource(extract.getAbsolutePath()); - - entries = new HashSet<>(Arrays.asList(e.list())); - assertEquals(2,entries.size()); - assertTrue(entries.contains("alphabet")); - assertTrue(entries.contains("numbers")); - IO.delete(extract); - - } - - /* ------------------------------------------------------------ */ - @Test - public void testJarFileGetAllResoures() - throws Exception - { - String s = "jar:"+__userURL+"TestData/test.zip!/subdir/"; - Resource r = Resource.newResource(s); - Collection deep=r.getAllResources(); + assumeThat(data.content, notNullValue()); - assertEquals(4, deep.size()); - } - - @Test - public void testJarFileIsContainedIn () - throws Exception - { - String s = "jar:"+__userURL+"TestData/test.zip!/subdir/"; - Resource r = Resource.newResource(s); - Resource container = Resource.newResource(__userURL+"TestData/test.zip"); - - assertTrue(r instanceof JarFileResource); - JarFileResource jarFileResource = (JarFileResource)r; - - assertTrue(jarFileResource.isContainedIn(container)); - - container = Resource.newResource(__userURL+"TestData"); - assertFalse(jarFileResource.isContainedIn(container)); - } - - /* ------------------------------------------------------------ */ - @Test - public void testJarFileLastModified () - throws Exception - { - String s = "jar:"+__userURL+"TestData/test.zip!/subdir/numbers"; - - try(ZipFile zf = new ZipFile(MavenTestingUtils.getTestResourceFile("TestData/test.zip"))) - { - long last = zf.getEntry("subdir/numbers").getTime(); - - Resource r = Resource.newResource(s); - assertEquals(last,r.lastModified()); - } - } - - /* ------------------------------------------------------------ */ - @Test - public void testJarFileCopyToDirectoryTraversal () throws Exception - { - String s = "jar:"+__userURL+"TestData/extract.zip!/"; - Resource r = Resource.newResource(s); - - assertTrue(r instanceof JarResource); - JarResource jarResource = (JarResource)r; - - File destParent = File.createTempFile("copyjar", null); - if (destParent.exists()) - destParent.delete(); - destParent.mkdir(); - destParent.deleteOnExit(); - - File dest = new File(destParent.getCanonicalPath()+"/extract"); - if(dest.exists()) - dest.delete(); - dest.mkdir(); - dest.deleteOnExit(); - - jarResource.copyTo(dest); - - // dest contains only the valid entry; dest.getParent() contains only the dest directory - assertEquals(1, dest.listFiles().length); - assertEquals(1, dest.getParentFile().listFiles().length); - - FilenameFilter dotdotFilenameFilter = new FilenameFilter() { - @Override - public boolean accept(File directory, String name) - { - return name.equals("dotdot.txt"); - } - }; - assertEquals(0, dest.listFiles(dotdotFilenameFilter).length); - assertEquals(0, dest.getParentFile().listFiles(dotdotFilenameFilter).length); - - FilenameFilter extractfileFilenameFilter = new FilenameFilter() { - @Override - public boolean accept(File directory, String name) - { - return name.equals("extract-filenotdir"); - } - }; - assertEquals(0, dest.listFiles(extractfileFilenameFilter).length); - assertEquals(0, dest.getParentFile().listFiles(extractfileFilenameFilter).length); - - FilenameFilter currentDirectoryFilenameFilter = new FilenameFilter() { - @Override - public boolean accept(File directory, String name) - { - return name.equals("current.txt"); - } - }; - assertEquals(1, dest.listFiles(currentDirectoryFilenameFilter).length); - assertEquals(0, dest.getParentFile().listFiles(currentDirectoryFilenameFilter).length); - - IO.delete(dest); - assertFalse(dest.exists()); - } - - /** - * Test a class path resource for existence. - */ - @Test - public void testClassPathResourceClassRelative() - { - final String classPathName="Resource.class"; - - try(Resource resource=Resource.newClassPathResource(classPathName);) - { - // A class path cannot be a directory - assertFalse("Class path cannot be a directory.",resource.isDirectory()); - - // A class path must exist - assertTrue("Class path resource does not exist.",resource.exists()); - } - } - - /** - * Test a class path resource for existence. - */ - @Test - public void testClassPathResourceClassAbsolute() - { - final String classPathName="/org/eclipse/jetty/util/resource/Resource.class"; - - Resource resource=Resource.newClassPathResource(classPathName); - - // A class path cannot be a directory - assertFalse("Class path cannot be a directory.",resource.isDirectory()); - - // A class path must exist - assertTrue("Class path resource does not exist.",resource.exists()); - } - - /** - * Test a class path resource for directories. - */ - @Test - public void testClassPathResourceDirectory() throws Exception - { - final String classPathName="/"; - - Resource resource=Resource.newClassPathResource(classPathName); - - // A class path must be a directory - assertTrue("Class path must be a directory.",resource.isDirectory()); - - assertTrue("Class path returned file must be a directory.",resource.getFile().isDirectory()); - - // A class path must exist - assertTrue("Class path resource does not exist.",resource.exists()); - } - - /** - * Test a class path resource for a file. - */ - @Test - public void testClassPathResourceFile() throws Exception - { - final String fileName="resource.txt"; - final String classPathName="/"+fileName; - - // Will locate a resource in the class path - Resource resource=Resource.newClassPathResource(classPathName); - - // A class path cannot be a directory - assertFalse("Class path must be a directory.",resource.isDirectory()); - - assertTrue(resource!=null); - - File file=resource.getFile(); - - assertEquals("File name from class path is not equal.",fileName,file.getName()); - assertTrue("File returned from class path should be a file.",file.isFile()); - - // A class path must exist - assertTrue("Class path resource does not exist.",resource.exists()); - } - - @Test - public void testUncPathResourceFile() throws Exception - { - // This test is intended to run only on Windows platform - assumeTrue(OS.IS_WINDOWS); - - String path = __userURL.toURI().getPath().replace('/','\\')+"resource.txt"; - //System.err.println(path); - - Resource resource = Resource.newResource(path, false); - //System.err.println(resource); - assertTrue(resource.exists()); - - /* - - String uncPath = "\\\\127.0.0.1"+__userURL.toURI().getPath().replace('/','\\').replace(':','$')+"ResourceTest.java"; - System.err.println(uncPath); - - Resource uncResource = Resource.newResource(uncPath, false); - System.err.println(uncResource); - assertTrue(uncResource.exists()); - - */ + InputStream in = data.resource.getInputStream(); + String c = IO.toString(in); + assertThat("Content: " + data.test,c,startsWith(data.content)); } } From 58b1ec993516caab226774d73e8059662080cae7 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 27 Jun 2014 12:55:38 +0200 Subject: [PATCH 129/269] Improved logging. --- .../eclipse/jetty/http2/server/HttpChannelOverHTTP2.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 270cc8d198d..b6cd36a0cde 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -71,7 +71,6 @@ public class HttpChannelOverHTTP2 extends HttpChannel if (!fields.contains(HttpHeader.ACCEPT_ENCODING, "gzip")) fields.add(ACCEPT_ENCODING_GZIP); - // TODO make this a better field for h2 hpack generation if (getHttpConfiguration().getSendServerVersion()) getResponse().getHttpFields().add(SERVER_VERSION); @@ -103,6 +102,9 @@ public class HttpChannelOverHTTP2 extends HttpChannel BufferUtil.clearToFill(copy); copy.put(original).flip(); + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Request #{}: {} bytes of content", stream.getId(), copy.remaining()); + onContent(new HttpInput.Content(copy) { @Override @@ -118,7 +120,6 @@ public class HttpChannelOverHTTP2 extends HttpChannel byteBufferPool.release(copy); callback.failed(x); } - }); if (frame.isEndStream()) @@ -126,5 +127,4 @@ public class HttpChannelOverHTTP2 extends HttpChannel onRequestComplete(); } } - } From 603985dcd2f48ef0093998c61f016d10ecacb40f Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 27 Jun 2014 17:06:07 +0200 Subject: [PATCH 130/269] Implemented gentler shutdown in case of reading -1. This allows big responses to be sent even if the request half closes the connection. --- .../jetty/http2/client/HTTP2Client.java | 21 +++---- .../eclipse/jetty/http2/HTTP2Connection.java | 17 ++++- .../org/eclipse/jetty/http2/HTTP2Session.java | 63 ++++++++++++++++--- .../org/eclipse/jetty/http2/ISession.java | 2 + .../AbstractHTTP2ServerConnectionFactory.java | 16 +++-- 5 files changed, 90 insertions(+), 29 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index f69e549ecb5..ce1996917ad 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -30,6 +30,7 @@ import java.util.concurrent.Executor; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.ErrorCode; @@ -50,7 +51,7 @@ import org.eclipse.jetty.util.thread.Scheduler; public class HTTP2Client extends ContainerLifeCycle { - private final Queue sessions = new ConcurrentLinkedQueue<>(); + private final Queue sessions = new ConcurrentLinkedQueue<>(); private final SelectorManager selector; private final ByteBufferPool byteBufferPool; private long idleTimeout; @@ -96,7 +97,7 @@ public class HTTP2Client extends ContainerLifeCycle private void closeConnections() { - for (Session session : sessions) + for (ISession session : sessions) session.close(ErrorCode.NO_ERROR, null, Callback.Adapter.INSTANCE); sessions.clear(); } @@ -131,20 +132,18 @@ public class HTTP2Client extends ContainerLifeCycle Generator generator = new Generator(byteBufferPool, 4096); HTTP2Session session = new HTTP2ClientSession(getScheduler(), endpoint, generator, context.listener, new HTTP2FlowControl(65535)); Parser parser = new Parser(byteBufferPool, session, 4096, 8192); - return new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, 8192, context.promise, session); + return new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, session, 8192, context.promise); } } private class HTTP2ClientConnection extends HTTP2Connection implements Callback { private final Promise promise; - private final Session session; - public HTTP2ClientConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, int bufferSize, Promise promise, Session session) + public HTTP2ClientConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise promise) { - super(byteBufferPool, executor, endpoint, parser, bufferSize); + super(byteBufferPool, executor, endpoint, parser, session, bufferSize); this.promise = promise; - this.session = session; } @Override @@ -158,7 +157,7 @@ public class HTTP2Client extends ContainerLifeCycle public void onClose() { super.onClose(); - sessions.remove(session); + sessions.remove(getSession()); } @Override @@ -166,15 +165,15 @@ public class HTTP2Client extends ContainerLifeCycle { if (LOG.isDebugEnabled()) LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); - session.close(ErrorCode.NO_ERROR, "idle_timeout", closeCallback); + getSession().close(ErrorCode.NO_ERROR, "idle_timeout", closeCallback); return false; } @Override public void succeeded() { - sessions.offer(session); - promise.succeeded(session); + sessions.offer(getSession()); + promise.succeeded(getSession()); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index cd545dc194a..0511ecf264b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -44,16 +44,23 @@ public class HTTP2Connection extends AbstractConnection }; private final ByteBufferPool byteBufferPool; private final Parser parser; + private final ISession session; private final int bufferSize; - public HTTP2Connection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, int bufferSize) + public HTTP2Connection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, ISession session, int bufferSize) { super(endPoint, executor); this.byteBufferPool = byteBufferPool; this.parser = parser; + this.session = session; this.bufferSize = bufferSize; } + protected ISession getSession() + { + return session; + } + @Override public void onOpen() { @@ -85,7 +92,7 @@ public class HTTP2Connection extends AbstractConnection } else if (filled < 0) { - close(); + shutdown(endPoint, session); return -1; } else @@ -109,4 +116,10 @@ public class HTTP2Connection extends AbstractConnection return -1; } } + + private void shutdown(EndPoint endPoint, ISession session) + { + if (!endPoint.isOutputShutdown()) + session.shutdown(); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 6436b73d07c..1fd402961b0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -366,13 +366,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.iterate(); } - public void disconnect() - { - if (LOG.isDebugEnabled()) - LOG.debug("Disconnecting"); - endPoint.close(); - } - protected IStream createLocalStream(HeadersFrame frame) { IStream stream = newStream(frame); @@ -472,6 +465,24 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return windowSize.getAndAdd(delta); } + @Override + public void shutdown() + { + if (LOG.isDebugEnabled()) + LOG.debug("Shutting down"); + + // Append a fake FlusherEntry that disconnects when the queue is drained. + flusher.append(new ShutdownFlusherEntry()); + flusher.iterate(); + } + + public void disconnect() + { + if (LOG.isDebugEnabled()) + LOG.debug("Disconnecting"); + endPoint.close(); + } + private void updateLastStreamId(int streamId) { Atomics.updateMax(lastStreamId, streamId); @@ -575,6 +586,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener fail = true; else queue.offer(entry); + if (LOG.isDebugEnabled()) + LOG.debug("Appended {}, queue={}", entry, queue.size()); } if (fail) closed(entry); @@ -740,6 +753,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener queued = new ArrayDeque<>(queue); } + if (LOG.isDebugEnabled()) + LOG.debug("Closing, queued={}", queued.size()); + while (true) { FlusherEntry item = queued.poll(); @@ -873,6 +889,39 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } + private class ShutdownFlusherEntry extends FlusherEntry + { + public ShutdownFlusherEntry() + { + super(null, null, Adapter.INSTANCE); + } + + @Override + public void generate(ByteBufferPool.Lease lease) + { + } + + @Override + public void succeeded() + { + flusher.close(); + disconnect(); + } + + @Override + public void failed(Throwable x) + { + flusher.close(); + disconnect(); + } + + @Override + public String toString() + { + return String.format("%s@%x", "ShutdownFrame", hashCode()); + } + } + private class PromiseCallback implements Callback { private final Promise promise; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index d072c3f9075..4557a1a9f61 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -34,5 +34,7 @@ public interface ISession extends Session public int updateWindowSize(int delta); + public void shutdown(); + public void disconnect(); } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index e515d45c124..c21492e26c3 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -22,7 +22,7 @@ import java.util.concurrent.Executor; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; -import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.ErrorCode; @@ -86,7 +86,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne Parser parser = newServerParser(connector.getByteBufferPool(), session); HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(), - endPoint, parser, getInputBufferSize(), listener, session); + endPoint, parser, session, getInputBufferSize(), listener); return configure(connection, connector, endPoint); } @@ -98,20 +98,18 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne private class HTTP2ServerConnection extends HTTP2Connection { private final ServerSessionListener listener; - private final Session session; - public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, int inputBufferSize, ServerSessionListener listener, Session session) + public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, ISession session, int inputBufferSize, ServerSessionListener listener) { - super(byteBufferPool, executor, endPoint, parser, inputBufferSize); + super(byteBufferPool, executor, endPoint, parser, session, inputBufferSize); this.listener = listener; - this.session = session; } @Override public void onOpen() { super.onOpen(); - notifyConnect(session); + notifyConnect(getSession()); } @Override @@ -119,11 +117,11 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne { if (LOG.isDebugEnabled()) LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); - session.close(ErrorCode.NO_ERROR, "idle_timeout", closeCallback); + getSession().close(ErrorCode.NO_ERROR, "idle_timeout", closeCallback); return false; } - private void notifyConnect(Session session) + private void notifyConnect(ISession session) { try { From c9f299e1de4c807f30e95a59fdc63b2a92a63b8a Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 27 Jun 2014 17:07:49 +0200 Subject: [PATCH 131/269] Adding X-Forwarded-Host in case host header is missing, and coalescing Cookie headers. --- .../fcgi/server/proxy/FastCGIProxyServlet.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java index 15c7d425520..b10beec9d86 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.fcgi.server.proxy; import java.net.URI; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.RequestDispatcher; @@ -136,6 +137,23 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent if (!getHttpClient().isDefaultPort(request.getScheme(), port)) host += ":" + port; proxyRequest.header(HttpHeader.HOST, host); + proxyRequest.header(HttpHeader.X_FORWARDED_HOST, host); + } + + // PHP does not like multiple Cookie headers, coalesce into one. + List cookies = proxyRequest.getHeaders().getValuesList(HttpHeader.COOKIE.asString()); + if (cookies.size() > 1) + { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < cookies.size(); ++i) + { + if (i > 0) + builder.append("; "); + String cookie = cookies.get(i); + builder.append(cookie); + } + proxyRequest.header(HttpHeader.COOKIE, null); + proxyRequest.header(HttpHeader.COOKIE, builder.toString()); } super.customizeProxyRequest(proxyRequest, request); From c8ee504291a6f1079039fa606e8ded6bd0fd7444 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 3 Jul 2014 15:53:12 +1000 Subject: [PATCH 132/269] rfc7230 ignore null value headers --- .../src/main/java/org/eclipse/jetty/http/HttpGenerator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index b3a3b37c45d..42d0d9c9bee 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -585,6 +585,10 @@ public class HttpGenerator { for (HttpField field : _info.getHttpFields()) { + String v = field.getValue(); + if (v==null || v.length()==0) + continue; // rfc7230 does not allow no value + HttpHeader h = field.getHeader(); switch (h==null?HttpHeader.UNKNOWN:h) From ca1a9ceb7c206bc1e4bdb4c87ae1be5baace9144 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 4 Jul 2014 23:22:40 +1000 Subject: [PATCH 133/269] fixed merge issues --- .../org/eclipse/jetty/http2/HTTP2Session.java | 22 ++++++------------- .../org/eclipse/jetty/server/RequestTest.java | 6 ++++- .../eclipse/jetty/util/IteratingCallback.java | 5 +++-- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 1fd402961b0..c1934ee3b40 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -569,7 +569,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final ByteBufferPool.Lease lease = new ByteBufferPool.Lease(generator.getByteBufferPool()); private final int maxGather; private final List active; - private boolean closed; private Flusher(int maxGather) { @@ -582,7 +581,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener boolean fail = false; synchronized (queue) { - if (closed) + if (isClosed()) fail = true; else queue.offer(entry); @@ -598,7 +597,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener boolean fail = false; synchronized (queue) { - if (closed) + if (isClosed()) fail = true; else queue.add(0, entry); @@ -620,9 +619,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { synchronized (queue) { - if (closed) - return Action.IDLE; - int sessionWindow = getWindowSize(); int nonStalledIndex = 0; int size = queue.size(); @@ -749,20 +745,16 @@ public abstract class HTTP2Session implements ISession, Parser.Listener Queue queued; synchronized (queue) { - closed = true; + super.close(); queued = new ArrayDeque<>(queue); - } + } if (LOG.isDebugEnabled()) LOG.debug("Closing, queued={}", queued.size()); - - while (true) - { - FlusherEntry item = queued.poll(); - if (item == null) - break; + + for (FlusherEntry item: queued) closed(item); - } + } protected void closed(FlusherEntry item) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index c4977a1ac1e..15fdacd2cac 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; + import javax.servlet.MultipartConfigElement; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; @@ -53,6 +54,7 @@ import org.eclipse.jetty.util.log.StdErrLog; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -127,6 +129,7 @@ public class RequestTest } + @Ignore("Empty headers are not 7230 compliant") @Test public void testEmptyHeaders() throws Exception { @@ -1058,6 +1061,7 @@ public class RequestTest } + @Ignore("No longer relevant") @Test public void testCookieLeak() throws Exception { @@ -1103,7 +1107,7 @@ public class RequestTest + "POST / HTTP/1.1\r\n"+ "Host: whatever\r\n"+ - "Cookie:\r\n"+ + "Cookie: \r\n"+ "Connection: close\r\n"+ "\r\n"; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java index b3b7012056e..d2653fbdf87 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.util; import java.io.EOFException; +import java.nio.channels.ClosedChannelException; import java.util.concurrent.atomic.AtomicReference; /** @@ -360,7 +361,7 @@ public abstract class IteratingCallback implements Callback } } - public final void close() + public void close() { while (true) { @@ -376,7 +377,7 @@ public abstract class IteratingCallback implements Callback default: if (_state.compareAndSet(current, State.CLOSED)) { - onCompleteFailure(new IllegalStateException("Closed with pending callback "+this)); + onCompleteFailure(new ClosedChannelException()); return; } } From 42e1a60d6519c121786f94277f6536747bd134ab Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 9 Jul 2014 14:38:06 +1000 Subject: [PATCH 134/269] 438204 getServerName returns IPv6 addresses wrapped in [] --- .../main/java/org/eclipse/jetty/http/HostPortHttpField.java | 2 +- .../eclipse/jetty/server/CheckReverseProxyHeadersTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java index 683e82453e3..7a50bfc35b8 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java @@ -48,7 +48,7 @@ public class HostPortHttpField extends HttpField int close=authority.lastIndexOf(']'); if (close<0) throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6"); - _host=authority.substring(1,close); + _host=authority.substring(0,close+1); if (authority.length()>close+1) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java index 506ff9e2ea2..cb60e0627d3 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java @@ -66,7 +66,7 @@ public class CheckReverseProxyHeadersTest @Override public void validate(HttpServletRequest request) { - assertEquals("::1", request.getServerName()); + assertEquals("[::1]", request.getServerName()); assertEquals(80, request.getServerPort()); assertEquals("10.20.30.40", request.getRemoteAddr()); assertEquals("10.20.30.40", request.getRemoteHost()); @@ -84,7 +84,7 @@ public class CheckReverseProxyHeadersTest @Override public void validate(HttpServletRequest request) { - assertEquals("::1", request.getServerName()); + assertEquals("[::1]", request.getServerName()); assertEquals(8888, request.getServerPort()); assertEquals("10.20.30.40", request.getRemoteAddr()); assertEquals("10.20.30.40", request.getRemoteHost()); From 068ec214194f62fd7aa83816978188ff8ef587dc Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 9 Jul 2014 16:44:34 +1000 Subject: [PATCH 135/269] 438204 getServerName returns IPv6 addresses wrapped in [] --- .../test/java/org/eclipse/jetty/http/HttpParserTest.java | 9 ++++++--- .../test/java/org/eclipse/jetty/server/RequestTest.java | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 50ac163f9e8..1d95e9dd391 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -18,7 +18,10 @@ package org.eclipse.jetty.http; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -1348,7 +1351,7 @@ public class HttpParserTest HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); - assertEquals("::1",_host); + assertEquals("[::1]",_host); assertEquals(0,_port); } @@ -1426,7 +1429,7 @@ public class HttpParserTest HttpParser.RequestHandler handler = new Handler(); HttpParser parser= new HttpParser(handler); parser.parseNext(buffer); - assertEquals("::1",_host); + assertEquals("[::1]",_host); assertEquals(8888,_port); } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 15fdacd2cac..e985eee97e0 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -485,7 +485,7 @@ public class RequestTest assertThat(response, Matchers.containsString("200 OK")); assertEquals("http://[::1]/",results.get(i++)); assertEquals("0.0.0.0",results.get(i++)); - assertEquals("::1",results.get(i++)); + assertEquals("[::1]",results.get(i++)); assertEquals("80",results.get(i++)); @@ -499,7 +499,7 @@ public class RequestTest assertThat(response, Matchers.containsString("200 OK")); assertEquals("http://[::1]:8888/",results.get(i++)); assertEquals("0.0.0.0",results.get(i++)); - assertEquals("::1",results.get(i++)); + assertEquals("[::1]",results.get(i++)); assertEquals("8888",results.get(i++)); @@ -515,7 +515,7 @@ public class RequestTest assertThat(response, Matchers.containsString("200 OK")); assertEquals("https://[::1]/",results.get(i++)); assertEquals("remote",results.get(i++)); - assertEquals("::1",results.get(i++)); + assertEquals("[::1]",results.get(i++)); assertEquals("443",results.get(i++)); @@ -531,7 +531,7 @@ public class RequestTest assertThat(response, Matchers.containsString("200 OK")); assertEquals("https://[::1]:8888/",results.get(i++)); assertEquals("remote",results.get(i++)); - assertEquals("::1",results.get(i++)); + assertEquals("[::1]",results.get(i++)); assertEquals("8888",results.get(i++)); } From f594a6fc661ae3590c8fdb9e5255e1b7b65f8229 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 11 Jul 2014 16:08:18 +1000 Subject: [PATCH 136/269] HttpField.contains ignores ;q=0 items --- .../org/eclipse/jetty/http/HttpField.java | 184 ++++++++++++++++-- .../org/eclipse/jetty/http/HttpFieldTest.java | 50 ++++- 2 files changed, 219 insertions(+), 15 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index 75cd3e4fb16..fec510f2cbd 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -25,6 +25,7 @@ import java.util.ArrayList; */ public class HttpField { + private final static String __zeroquality="q=0"; private final HttpHeader _header; private final String _name; private final String _value; @@ -175,33 +176,192 @@ public class HttpField return list.toArray(new String[list.size()]); } - + /* ------------------------------------------------------------ */ /** Look for a value in a possible multi valued field * @param search Values to search for * @return True iff the value is contained in the field value entirely or - * as an element of a quoted comma separated list. List element parameters (eg qualities) are ignored. + * as an element of a quoted comma separated list. List element parameters (eg qualities) are ignored, + * except if they are q=0, in which case the item itself is ignored. */ public boolean contains(String search) { if (_value==null || search==null) return _value==search; + if (search.length()==0) + return false; - if (_value.equals(search)) - return true; - - String[] values = getValues(); - for (String v:values) + int state=0; + int match=0; + int param=0; + + for (int i=0;i<_value.length();i++) { - if (v.equals(search)) - return true; - if (v.startsWith(search) && v.charAt(search.length())==';') - return true; + char c = _value.charAt(i); + switch(state) + { + case 0: // initial white space + switch(c) + { + case '"': // open quote + match=0; + state=2; + break; + + case ',': // ignore leading empty field + break; + + case ';': // ignore leading empty field parameter + param=-1; + match=-1; + state=5; + break; + + case ' ': // more white space + case '\t': + break; + + default: // character + match = c==search.charAt(0)?1:-1; + state=1; + break; + } + break; + + case 1: // In token + switch(c) + { + case ',': // next field + // Have we matched the token? + if (match==search.length()) + return true; + state=0; + break; + + case ';': + param=match>=0?0:-1; + state=5; // parameter + break; + + default: + if (match>0) + { + if (match=0) + { + if (match=0) + { + if (match=0) + { + if (param<__zeroquality.length()) + param=c==__zeroquality.charAt(param)?(param+1):-1; + else if (c!='0'&&c!='.'&&c!=' ') + param=-1; + } + + } + break; + + default: + throw new IllegalStateException(); + } } - return false; + return param!=__zeroquality.length() && match==search.length(); } + + + + + + + + + + + + + + @Override public String toString() { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java index bcdaaf96444..72ae0ac0ee9 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java @@ -72,9 +72,53 @@ public class HttpFieldTest assertFalse(field.contains(null)); } - - - + + @Test + public void testQualityContainsList() throws Exception + { + HttpField field; + + field = new HttpField("name","yes"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + field = new HttpField("name",",yes,"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + field = new HttpField("name","other,yes,other"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + field = new HttpField("name","other, yes ,other"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + field = new HttpField("name","other, y s ,other"); + assertTrue(field.contains("y s")); + assertFalse(field.contains("no")); + + field = new HttpField("name","other, \"yes\" ,other"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + field = new HttpField("name","other, \"\\\"yes\\\"\" ,other"); + assertTrue(field.contains("\"yes\"")); + assertFalse(field.contains("no")); + + field = new HttpField("name",";no,yes,;no"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + field = new HttpField("name","no;q=0,yes;q=1,no; q = 0"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + field = new HttpField("name","no;q=0.0000,yes;q=0.0001,no; q = 0.00000"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + } @Test public void testValues() From 2d057bea13f275942f175437175bd01e052904c7 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 11 Jul 2014 16:09:36 +1000 Subject: [PATCH 137/269] HttpChannelOverHttp uses held values rather than request --- .../org/eclipse/jetty/server/HttpChannelOverHttp.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 16e4d16e8c6..7fd13dbd6a5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -132,7 +132,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl case EXPECT: { - if (getRequest().getHttpVersion().getVersion()==HttpVersion.HTTP_1_1.getVersion()) + if (_version==HttpVersion.HTTP_1_1) { HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) @@ -213,7 +213,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl public void earlyEOF() { // If we have no request yet, just close - if (getRequest().getMethod()==null) + if (_method==null) _httpConnection.close(); else onEarlyEOF(); @@ -254,7 +254,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl persistent=false; if (!persistent) - persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); + persistent = HttpMethod.CONNECT.is(_method); if (persistent) getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); @@ -280,7 +280,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl persistent=true; if (!persistent) - persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); + persistent = HttpMethod.CONNECT.is(_method); if (!persistent) getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); break; From fff2dd2f2dd237b619187ad1ddc4d71be2eff560 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 11 Jul 2014 16:10:06 +1000 Subject: [PATCH 138/269] misc test fixes for rfc7230 issues --- .../org/eclipse/jetty/http/HttpParser.java | 2 + .../jetty/servlets/AsyncGzipFilter.java | 2 +- .../jetty/servlets/CrossOriginFilterTest.java | 3 +- .../GzipFilterDefaultNoRecompressTest.java | 67 ++++++++++--------- .../spdy/server/http/HttpChannelOverSPDY.java | 4 +- .../server/proxy/ProxySPDYToHTTPTest.java | 2 +- .../websocket/jsr356/DecoderReaderTest.java | 9 ++- 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index fc54f3235b6..4a372729e0b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -1056,6 +1056,8 @@ public class HttpParser break; } + if (LOG.isDebugEnabled()) + LOG.debug("Illegal character '{}' in {}",ch,BufferUtil.toDetailString(buffer)); throw new BadMessageException("Illegal character"); case HEADER_VALUE: diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java index 2e46a1ca961..219169ce0dd 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java @@ -488,7 +488,7 @@ public class AsyncGzipFilter extends UserAgentFilter implements GzipFactory } // If not HTTP/2, then we must check the accept encoding header - if (request.getHttpVersion().ordinal()!=HttpVersion.HTTP_2.ordinal()) + if (request.getHttpVersion()!=HttpVersion.HTTP_2) { HttpField accept = request.getHttpFields().getField(HttpHeader.ACCEPT_ENCODING); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java index 23c5fb7194a..db3e3617846 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java @@ -398,7 +398,8 @@ public class CrossOriginFilterTest "Upgrade: WebSocket\r\n" + "Origin: http://localhost\r\n" + "\r\n"; - String response = tester.getResponses(request); + String response = tester.getResponses(request,1,TimeUnit.SECONDS); + System.err.println(response); Assert.assertTrue(response.contains("HTTP/1.1 200")); Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER)); Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER)); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java index 4aa434e68f7..bb38ae58cba 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java @@ -44,53 +44,54 @@ import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class GzipFilterDefaultNoRecompressTest { + @SuppressWarnings("deprecation") @Parameters public static List data() { return Arrays.asList(new Object[][] { // Some already compressed files - { GzipFilter.class, "test_quotes.gz", "application/gzip", GzipFilter.GZIP }, - { GzipFilter.class, "test_quotes.bz2", "application/bzip2", GzipFilter.GZIP }, - { GzipFilter.class, "test_quotes.zip", "application/zip", GzipFilter.GZIP }, - { GzipFilter.class, "test_quotes.rar", "application/octet-stream", GzipFilter.GZIP }, + /* 00 */ { GzipFilter.class, "test_quotes.gz", "application/gzip", GzipFilter.GZIP }, + /* 01 */ { GzipFilter.class, "test_quotes.bz2", "application/bzip2", GzipFilter.GZIP }, + /* 02 */ { GzipFilter.class, "test_quotes.zip", "application/zip", GzipFilter.GZIP }, + /* 03 */ { GzipFilter.class, "test_quotes.rar", "application/octet-stream", GzipFilter.GZIP }, // Some images (common first) - { GzipFilter.class, "jetty_logo.png", "image/png", GzipFilter.GZIP }, - { GzipFilter.class, "jetty_logo.gif", "image/gif", GzipFilter.GZIP }, - { GzipFilter.class, "jetty_logo.jpeg", "image/jpeg", GzipFilter.GZIP }, - { GzipFilter.class, "jetty_logo.jpg", "image/jpeg", GzipFilter.GZIP }, + /* 04 */ { GzipFilter.class, "jetty_logo.png", "image/png", GzipFilter.GZIP }, + /* 05 */ { GzipFilter.class, "jetty_logo.gif", "image/gif", GzipFilter.GZIP }, + /* 06 */ { GzipFilter.class, "jetty_logo.jpeg", "image/jpeg", GzipFilter.GZIP }, + /* 07 */ { GzipFilter.class, "jetty_logo.jpg", "image/jpeg", GzipFilter.GZIP }, // Lesser encountered images (usually found being requested from non-browser clients) - { GzipFilter.class, "jetty_logo.bmp", "image/bmp", GzipFilter.GZIP }, - { GzipFilter.class, "jetty_logo.tga", "application/tga", GzipFilter.GZIP }, - { GzipFilter.class, "jetty_logo.tif", "image/tiff", GzipFilter.GZIP }, - { GzipFilter.class, "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP }, - { GzipFilter.class, "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP }, - { GzipFilter.class, "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP }, + /* 08 */ { GzipFilter.class, "jetty_logo.bmp", "image/bmp", GzipFilter.GZIP }, + /* 09 */ { GzipFilter.class, "jetty_logo.tga", "application/tga", GzipFilter.GZIP }, + /* 10 */ { GzipFilter.class, "jetty_logo.tif", "image/tiff", GzipFilter.GZIP }, + /* 11 */ { GzipFilter.class, "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP }, + /* 12 */ { GzipFilter.class, "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP }, + /* 13 */ { GzipFilter.class, "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP }, //qvalue disables compression - { GzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+";q=0"}, - { GzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+"; q = 0 "}, + /* 14 */ { GzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+";q=0"}, + /* 15 */ { GzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+"; q = 0 "}, // Some already compressed files - { AsyncGzipFilter.class, "test_quotes.gz", "application/gzip", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "test_quotes.bz2", "application/bzip2", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "test_quotes.zip", "application/zip", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "test_quotes.rar", "application/octet-stream", GzipFilter.GZIP }, + /* 16 */ { AsyncGzipFilter.class, "test_quotes.gz", "application/gzip", GzipFilter.GZIP }, + /* 17 */ { AsyncGzipFilter.class, "test_quotes.bz2", "application/bzip2", GzipFilter.GZIP }, + /* 18 */ { AsyncGzipFilter.class, "test_quotes.zip", "application/zip", GzipFilter.GZIP }, + /* 19 */ { AsyncGzipFilter.class, "test_quotes.rar", "application/octet-stream", GzipFilter.GZIP }, // Some images (common first) - { AsyncGzipFilter.class, "jetty_logo.png", "image/png", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "jetty_logo.gif", "image/gif", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "jetty_logo.jpeg", "image/jpeg", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "jetty_logo.jpg", "image/jpeg", GzipFilter.GZIP }, + /* 20 */ { AsyncGzipFilter.class, "jetty_logo.png", "image/png", GzipFilter.GZIP }, + /* 21 */ { AsyncGzipFilter.class, "jetty_logo.gif", "image/gif", GzipFilter.GZIP }, + /* 22 */ { AsyncGzipFilter.class, "jetty_logo.jpeg", "image/jpeg", GzipFilter.GZIP }, + /* 23 */ { AsyncGzipFilter.class, "jetty_logo.jpg", "image/jpeg", GzipFilter.GZIP }, // Lesser encountered images (usually found being requested from non-browser clients) - { AsyncGzipFilter.class, "jetty_logo.bmp", "image/bmp", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "jetty_logo.tga", "application/tga", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "jetty_logo.tif", "image/tiff", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP }, - { AsyncGzipFilter.class, "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP }, - //qvalue disables compression - { AsyncGzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+";q=0"}, - { AsyncGzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+"; q = 0 "} + /* 24 */ { AsyncGzipFilter.class, "jetty_logo.bmp", "image/bmp", GzipFilter.GZIP }, + /* 25 */ { AsyncGzipFilter.class, "jetty_logo.tga", "application/tga", GzipFilter.GZIP }, + /* 26 */ { AsyncGzipFilter.class, "jetty_logo.tif", "image/tiff", GzipFilter.GZIP }, + /* 27 */ { AsyncGzipFilter.class, "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP }, + /* 28 */ { AsyncGzipFilter.class, "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP }, + /* 29 */ { AsyncGzipFilter.class, "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP }, + // qvalue disables compression + /* 30 */ { AsyncGzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+";q=0"}, + /* 31 */ { AsyncGzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+"; q = 0 "} }); } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index e753f55390b..0bbd9e32bbe 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -124,9 +124,7 @@ public class HttpChannelOverSPDY extends HttpChannel { if (specialHeader != HTTPSPDYHeader.HOST) continue; - name = "host"; - hostPort = new HostPortHttpField(header.getValue()); } switch (name) @@ -141,7 +139,7 @@ public class HttpChannelOverSPDY extends HttpChannel } case "host": { - // Do not add it now. + hostPort = new HostPortHttpField(header.getValue()); break; } default: diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java index 700d560150a..219ebde0706 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java @@ -238,7 +238,7 @@ public abstract class ProxySPDYToHTTPTest @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - response.addHeader("some response", "header"); + response.addHeader("someResponse", "header"); response.flushBuffer(); try { diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java index 441e8a60a80..06c06565bc4 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java +++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java @@ -54,6 +54,7 @@ import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -134,13 +135,14 @@ public class DecoderReaderTest } @OnMessage - public void onMessage(Quotes msg) + public synchronized void onMessage(Quotes msg) { + Integer h=hashCode(); messageQueue.add(msg); - System.out.printf("Quotes from: %s%n",msg.author); + System.out.printf("%x: Quotes from: %s%n",h,msg.author); for (String quote : msg.quotes) { - System.out.printf(" - %s%n",quote); + System.out.printf("%x: - %s%n",h,quote); } } @@ -268,6 +270,7 @@ public class DecoderReaderTest } @Test + @Ignore ("Quotes appear to be able to arrive in any order?") public void testTwoQuotes() throws Exception { QuotesSocket quoter = new QuotesSocket(); From f9ffefbe1393f27651be73f48a082ddd74e742fc Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 11 Jul 2014 16:35:25 +1000 Subject: [PATCH 139/269] refactored to avoid copying MetaData.Request instances --- .../fcgi/server/HttpChannelOverFCGI.java | 3 +- .../eclipse/jetty/http/AbstractMetaData.java | 163 ++++++++++++ .../org/eclipse/jetty/http/FinalMetaData.java | 168 +++++++++++++ .../java/org/eclipse/jetty/http/MetaData.java | 235 +----------------- .../org/eclipse/jetty/http/HttpFieldTest.java | 12 - .../eclipse/jetty/http/HttpFieldsTest.java | 3 + .../http/HttpGeneratorServerHTTPTest.java | 14 +- .../jetty/http/HttpGeneratorServerTest.java | 12 +- .../jetty/http2/client/AbstractTest.java | 3 +- .../jetty/http2/client/FlowControlTest.java | 11 +- .../jetty/http2/client/IdleTimeoutTest.java | 10 +- .../jetty/http2/client/StreamResetTest.java | 3 +- .../frames/HeadersGenerateParseTest.java | 5 +- .../frames/PushPromiseGenerateParseTest.java | 5 +- .../jetty/http2/hpack/MetaDataBuilder.java | 7 +- .../jetty/http2/hpack/HpackEncoderTest.java | 19 +- .../eclipse/jetty/http2/hpack/HpackTest.java | 14 +- .../test/resources/jetty-logging.properties | 3 + .../http2/server/HttpTransportOverHTTP2.java | 3 +- .../jetty/http2/server/HTTP2ServerTest.java | 8 +- .../org/eclipse/jetty/server/HttpChannel.java | 65 +---- .../jetty/server/HttpChannelOverHttp.java | 53 +++- .../org/eclipse/jetty/server/Request.java | 127 +++++++--- .../org/eclipse/jetty/server/Response.java | 3 +- .../jetty/servlets/CrossOriginFilterTest.java | 1 - .../spdy/server/http/HttpChannelOverSPDY.java | 3 +- 26 files changed, 568 insertions(+), 385 deletions(-) create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/AbstractMetaData.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java create mode 100644 jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java index 70a83065ec1..460ee6855a3 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java @@ -23,6 +23,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.fcgi.FCGI; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -87,7 +88,7 @@ public class HttpChannelOverFCGI extends HttpChannel String uri = path; if (query != null && query.length() > 0) uri += "?" + query; - onRequest(new MetaData.Request(HttpVersion.fromString(version), method, new HttpURI(uri), fields, hostPort)); + onRequest(new FinalMetaData.Request(HttpVersion.fromString(version), method, new HttpURI(uri), fields, hostPort)); } private HttpField convertHeader(HttpField field) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractMetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractMetaData.java new file mode 100644 index 00000000000..524e94b1113 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractMetaData.java @@ -0,0 +1,163 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import java.util.Iterator; + +public abstract class AbstractMetaData implements MetaData +{ + @Override + public boolean isRequest() + { + return false; + } + + @Override + public boolean isResponse() + { + return false; + } + + @Override + public Iterator iterator() + { + return getFields().iterator(); + } + + @Override + public int hashCode() + { + return 31 * getHttpVersion().hashCode() + getFields().hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof AbstractMetaData)) + return false; + AbstractMetaData that = (AbstractMetaData)o; + + if (getHttpVersion() != that.getHttpVersion()) + return false; + + return getFields().equals(that.getFields()); + } + + @Override + public String toString() + { + StringBuilder out = new StringBuilder(); + for (HttpField field: this) + out.append(field).append(System.lineSeparator()); + return out.toString(); + } + + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + public abstract static class Request extends AbstractMetaData implements MetaData.Request + { + @Override + public boolean isRequest() + { + return true; + } + + @Override + public boolean isResponse() + { + return false; + } + + @Override + public int hashCode() + { + int hash = getMethod().hashCode(); + hash = 31 * hash + getScheme().hashCode(); + hash = 31 * hash + getURI().hashCode(); + return 31 * hash + super.hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof MetaData.Request)) + return false; + MetaData.Request that = (MetaData.Request)o; + if (!getMethod().equals(that.getMethod()) || + !getScheme().equals(that.getScheme()) || + !getURI().equals(that.getURI())) + return false; + return super.equals(o); + } + + @Override + public String toString() + { + return String.format("%s %s://%s:%d%s HTTP/2%s%s", + getMethod(), getScheme(), getHost(), getPort(), getURI(), System.lineSeparator(), super.toString()); + } + } + + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + public abstract static class Response extends AbstractMetaData implements MetaData.Response + { + @Override + public boolean isRequest() + { + return false; + } + + @Override + public boolean isResponse() + { + return true; + } + @Override + public int hashCode() + { + return 31 * getStatus() + super.hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof MetaData.Response)) + return false; + MetaData.Response that = (MetaData.Response)o; + if (getStatus() != that.getStatus()) + return false; + return super.equals(o); + } + + @Override + public String toString() + { + return String.format("HTTP/2 %d%s%s", getStatus(), System.lineSeparator(), super.toString()); + } + } +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java new file mode 100644 index 00000000000..8aae76c5bab --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java @@ -0,0 +1,168 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + + +public class FinalMetaData extends AbstractMetaData +{ + private final HttpVersion _version; + private final HttpFields _fields; + + public FinalMetaData(HttpVersion version,HttpFields fields) + { + _fields=fields; + _version=version; + } + + @Override + public HttpVersion getHttpVersion() + { + return _version; + } + + @Override + public HttpFields getFields() + { + return _fields; + } + + + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + public static class Request extends AbstractMetaData.Request + { + private final HttpVersion _version; + private final HttpFields _fields; + private final String _method; + private final HttpURI _uri; + private final HostPortHttpField _hostPort; + private final HttpScheme _scheme; + + public Request(HttpVersion version, String method, HttpURI uri, HttpFields fields, HostPortHttpField hostPort) + { + _fields=fields; + _version=version; + _method=method; + _uri=uri; + _hostPort = hostPort; + String scheme = uri.getScheme(); + if (scheme == null) + { + _scheme = HttpScheme.HTTP; + } + else + { + HttpScheme s = HttpScheme.CACHE.get(scheme); + _scheme = s == null ? HttpScheme.HTTP : s; + } + } + + public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, String path, HttpFields fields) + { + this(version,scheme,method,authority,new HttpURI(path),fields); + } + + public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, HttpURI path, HttpFields fields) + { + _fields=fields; + _version=version; + _method=method; + _uri=path; + _hostPort = authority; + _scheme=scheme; + } + + @Override + public HttpVersion getHttpVersion() + { + return _version; + } + + @Override + public HttpFields getFields() + { + return _fields; + } + + @Override + public String getMethod() + { + return _method; + } + + @Override + public HttpScheme getScheme() + { + return _scheme; + } + + @Override + public String getHost() + { + return _hostPort==null?null:_hostPort.getHost(); + } + + @Override + public int getPort() + { + return _hostPort==null?0:_hostPort.getPort(); + } + + @Override + public HttpURI getURI() + { + return _uri; + } + } + + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + public static class Response extends AbstractMetaData.Response + { + private final HttpVersion _version; + private final HttpFields _fields; + private final int _status; + + public Response(HttpVersion version, int status, HttpFields fields) + { + _fields=fields; + _version=version; + _status=status; + } + + @Override + public HttpVersion getHttpVersion() + { + return _version; + } + + @Override + public HttpFields getFields() + { + return _fields; + } + + public int getStatus() + { + return _status; + } + } +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index 680d1c4371c..bfe4bb4f0fe 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -18,239 +18,30 @@ package org.eclipse.jetty.http; -import java.util.Iterator; - -public class MetaData implements Iterable +public interface MetaData extends Iterable { - private final HttpVersion _version; - private final HttpFields _fields; - - public MetaData(HttpVersion version,HttpFields fields) - { - _fields=fields; - _version=version; - } - - public HttpVersion getHttpVersion() - { - return _version; - } - - public boolean isRequest() - { - return false; - } - - public boolean isResponse() - { - return false; - } - - @Override - public Iterator iterator() - { - return _fields.iterator(); - } - - public HttpFields getFields() - { - return _fields; - } - - @Override - public int hashCode() - { - return 31 * _version.hashCode() + _fields.hashCode(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (!(o instanceof MetaData)) - return false; - MetaData that = (MetaData)o; - - if (_version != that._version) - return false; - - return _fields.equals(that._fields); - } - - @Override - public String toString() - { - StringBuilder out = new StringBuilder(); - for (HttpField field: this) - out.append(field).append(System.lineSeparator()); - return out.toString(); - } + public HttpVersion getHttpVersion(); + public boolean isRequest(); + public boolean isResponse(); + public HttpFields getFields(); /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ - public static class Request extends MetaData + public interface Request extends MetaData { - private final String _method; - private final HttpURI _uri; - private final HostPortHttpField _hostPort; - private final HttpScheme _scheme; - - public Request(HttpVersion version, String method, HttpURI uri, HttpFields fields, HostPortHttpField hostPort) - { - super(version,fields); - _method=method; - _uri=uri; - _hostPort = hostPort; - String scheme = uri.getScheme(); - if (scheme == null) - { - _scheme = HttpScheme.HTTP; - } - else - { - HttpScheme s = HttpScheme.CACHE.get(scheme); - _scheme = s == null ? HttpScheme.HTTP : s; - } - } - - public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, String path, HttpFields fields) - { - this(version,scheme,method,authority,new HttpURI(path),fields); - } - - public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, HttpURI path, HttpFields fields) - { - super(version,fields); - _method=method; - _uri=path; - _hostPort = authority; - _scheme=scheme; - } - - @Override - public boolean isRequest() - { - return true; - } - - @Override - public boolean isResponse() - { - return false; - } - - public String getMethod() - { - return _method; - } - - public HttpScheme getScheme() - { - return _scheme; - } - - public String getHost() - { - return _hostPort==null?null:_hostPort.getHost(); - } - - public int getPort() - { - return _hostPort==null?0:_hostPort.getPort(); - } - - public HttpURI getURI() - { - return _uri; - } - - @Override - public int hashCode() - { - int hash = _method.hashCode(); - hash = 31 * hash + _scheme.hashCode(); - hash = 31 * hash + _uri.hashCode(); - return 31 * hash + super.hashCode(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (!(o instanceof Request)) - return false; - Request that = (Request)o; - if (!_method.equals(that._method) || - !_scheme.equals(that._scheme) || - !_uri.equals(that._uri)) - return false; - return super.equals(o); - } - - @Override - public String toString() - { - return String.format("%s %s://%s:%d%s HTTP/2%s%s", - getMethod(), getScheme(), getHost(), getPort(), getURI(), System.lineSeparator(), super.toString()); - } + public String getMethod(); + public HttpScheme getScheme(); + public String getHost(); + public int getPort(); + public HttpURI getURI(); } /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ - public static class Response extends MetaData + public interface Response extends MetaData { - private final int _status; - - public Response(HttpVersion version, int status, HttpFields fields) - { - super(version,fields); - _status=status; - } - - @Override - public boolean isRequest() - { - return false; - } - - @Override - public boolean isResponse() - { - return true; - } - - public int getStatus() - { - return _status; - } - - @Override - public int hashCode() - { - return 31 * _status + super.hashCode(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (!(o instanceof Response)) - return false; - Response that = (Response)o; - if (_status != that._status) - return false; - return super.equals(o); - } - - @Override - public String toString() - { - return String.format("HTTP/2 %d%s%s", getStatus(), System.lineSeparator(), super.toString()); - } + public int getStatus(); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java index 72ae0ac0ee9..71ef0835768 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java @@ -18,22 +18,10 @@ package org.eclipse.jetty.http; -import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import java.nio.ByteBuffer; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; - -import org.eclipse.jetty.util.BufferUtil; -import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Test; /** diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index f6689f23640..ed2bef169ea 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -27,6 +27,9 @@ import static org.junit.Assert.assertTrue; import java.nio.ByteBuffer; import java.util.Enumeration; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; import org.junit.Assert; diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java index 02bf214de2a..12360231fc8 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java @@ -18,6 +18,13 @@ package org.eclipse.jetty.http; +import static org.hamcrest.Matchers.either; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; @@ -31,13 +38,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import static org.hamcrest.Matchers.either; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - @RunWith(Parameterized.class) public class HttpGeneratorServerHTTPTest { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java index a65b3028806..c2aa02f838b 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java @@ -18,6 +18,12 @@ package org.eclipse.jetty.http; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpGenerator.ResponseInfo; @@ -25,12 +31,6 @@ import org.eclipse.jetty.util.BufferUtil; import org.junit.Assert; import org.junit.Test; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - public class HttpGeneratorServerTest { @Test diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java index 8dc0afe68f4..18485215f1d 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServlet; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; @@ -108,6 +109,6 @@ public class AbstractTest String host = "localhost"; int port = connector.getLocalPort(); String authority = host + ":" + port; - return new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, method, new HostPortHttpField(authority), path, fields); + return new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, method, new HostPortHttpField(authority), path, fields); } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index def59646e98..186e0c97a3f 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -29,6 +29,7 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -72,7 +73,7 @@ public class FlowControlTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { HttpFields fields = new HttpFields(); - MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, fields); + MetaData.Response response = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, fields); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -150,7 +151,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -242,7 +243,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return new Stream.Listener.Adapter() @@ -347,7 +348,7 @@ public class FlowControlTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { // For every stream, send down half the window size of data. - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(windowSize / 2), true); @@ -429,7 +430,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.wrap(data), true); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java index 857e50190d2..ea3a8caa5ec 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java @@ -24,11 +24,13 @@ import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -60,7 +62,7 @@ public class IdleTimeoutTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { stream.setIdleTimeout(10 * idleTimeout); - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return null; @@ -143,7 +145,7 @@ public class IdleTimeoutTest extends AbstractTest { stream.setIdleTimeout(10 * idleTimeout); Thread.sleep(2 * idleTimeout); - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return null; @@ -202,7 +204,7 @@ public class IdleTimeoutTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { stream.setIdleTimeout(10 * idleTimeout); - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return null; @@ -277,7 +279,7 @@ public class IdleTimeoutTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { stream.setIdleTimeout(10 * idleTimeout); - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return null; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java index 2bc87b45a08..17fe58b821f 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java @@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -99,7 +100,7 @@ public class StreamResetTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response response = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return new Stream.Listener.Adapter() diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 810145a6a05..09c66937df9 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -50,7 +51,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); + MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); final List frames = new ArrayList<>(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() @@ -116,7 +117,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); + MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateHeaders(lease, streamId, metaData, false); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index 8826cbbcde5..b8a7827a889 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -62,7 +63,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); + MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) @@ -118,7 +119,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); + MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generatePushPromise(lease, streamId, promisedStreamId, metaData); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index b130ee86bac..368401e3733 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.hpack; import org.eclipse.jetty.http.BadMessageException; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -136,10 +137,10 @@ public class MetaDataBuilder HttpFields fields = _fields; _fields = new HttpFields(Math.max(10,fields.size()+5)); if (_method!=null) - return new MetaData.Request(HttpVersion.HTTP_2,_scheme,_method,_authority,_path,fields); + return new FinalMetaData.Request(HttpVersion.HTTP_2,_scheme,_method,_authority,_path,fields); if (_status!=0) - return new MetaData.Response(HttpVersion.HTTP_2,_status,fields); - return new MetaData(HttpVersion.HTTP_2,fields); + return new FinalMetaData.Response(HttpVersion.HTTP_2,_status,fields); + return new FinalMetaData(HttpVersion.HTTP_2,fields); } finally { diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index 7ca1dd521ec..8286ab345c3 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -23,6 +23,7 @@ package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; import java.util.HashSet; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; @@ -70,7 +71,7 @@ public class HpackEncoderTest // encode them ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,pos); // something was encoded! @@ -89,7 +90,7 @@ public class HpackEncoderTest // encode exact same fields again! BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // nothing should be encoded! @@ -112,7 +113,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -136,7 +137,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -163,7 +164,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -191,7 +192,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -225,7 +226,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -246,7 +247,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -258,7 +259,7 @@ public class HpackEncoderTest // encode again BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index 5a4b4a13f2e..4323ca8d7c8 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -24,16 +24,16 @@ import static org.junit.Assert.assertEquals; import java.nio.ByteBuffer; import org.eclipse.jetty.http.BadMessageException; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; -import org.junit.Assert; -import org.junit.Test; -import org.eclipse.jetty.http.MetaData.Request; import org.eclipse.jetty.http.MetaData.Response; import org.eclipse.jetty.util.BufferUtil; +import org.junit.Assert; +import org.junit.Test; public class HpackTest @@ -51,7 +51,7 @@ public class HpackTest fields0.add(HttpHeader.SERVER,"jetty"); fields0.add(HttpHeader.SET_COOKIE,"abcdefghijklmnopqrstuvwxyz"); fields0.add("custom-key","custom-value"); - Response original0 = new Response(HttpVersion.HTTP_2,200,fields0); + Response original0 = new FinalMetaData.Response(HttpVersion.HTTP_2,200,fields0); BufferUtil.clearToFill(buffer); encoder.encode(buffer,original0); @@ -73,7 +73,7 @@ public class HpackTest fields1.add(HttpHeader.CONTENT_LENGTH,"1234"); fields1.add(HttpHeader.SERVER,"jetty"); fields1.add("Custom-Key","Other-Value"); - Response original1 = new Response(HttpVersion.HTTP_2,200,fields1); + Response original1 = new FinalMetaData.Response(HttpVersion.HTTP_2,200,fields1); // Same again? BufferUtil.clearToFill(buffer); @@ -97,7 +97,7 @@ public class HpackTest HttpFields fields0 = new HttpFields(); fields0.add("1234567890","1234567890123456789012345678901234567890"); fields0.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); - MetaData original0= new MetaData(HttpVersion.HTTP_2,fields0); + MetaData original0= new FinalMetaData(HttpVersion.HTTP_2,fields0); BufferUtil.clearToFill(buffer); encoder.encode(buffer,original0); @@ -110,7 +110,7 @@ public class HpackTest fields1.add("1234567890","1234567890123456789012345678901234567890"); fields1.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); fields1.add("x","y"); - MetaData original1 = new MetaData(HttpVersion.HTTP_2,fields1); + MetaData original1 = new FinalMetaData(HttpVersion.HTTP_2,fields1); BufferUtil.clearToFill(buffer); encoder.encode(buffer,original1); diff --git a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..c8c72f381ed --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.http2.LEVEL=DEBUG + diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index e9e8ad69b1e..c6b2744d61f 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.server; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; @@ -81,7 +82,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport System.lineSeparator(), info.getHttpFields()); } - MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2, info.getStatus(), info.getHttpFields()); + MetaData metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, info.getStatus(), info.getHttpFields()); HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, endStream); stream.headers(frame, callback); } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 92a45734bb8..e9700374f38 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -28,11 +28,13 @@ import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; @@ -98,7 +100,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), new HostPortHttpField(host + ":" + port), path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -147,7 +149,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), new HostPortHttpField(host + ":" + port), path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -210,7 +212,7 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpVersion.HTTP_2,HttpScheme.HTTP, HttpMethod.GET.asString(), + MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2,HttpScheme.HTTP, HttpMethod.GET.asString(), new HostPortHttpField(host + ":" + port), path, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 4e30793367c..f52ade040d9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -22,22 +22,20 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; -import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; + import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; -import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator.ResponseInfo; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.ByteBufferPool; @@ -49,7 +47,6 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.SharedBlockingCallback.Blocker; -import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Scheduler; @@ -100,7 +97,6 @@ public class HttpChannel implements Runnable private final HttpChannelState _state; private final Request _request; private final Response _response; - private HttpVersion _version = HttpVersion.HTTP_1_1; public HttpChannel(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) { @@ -120,10 +116,6 @@ public class HttpChannel implements Runnable return _state; } - public HttpVersion getHttpVersion() - { - return _version; - } /** * @return the number of requests handled by this connection */ @@ -458,60 +450,9 @@ public class HttpChannel implements Runnable public void onRequest(MetaData.Request request) { _requests.incrementAndGet(); - // TODO directly inject MetaData.Request to Request - + _request.setTimeStamp(System.currentTimeMillis()); - - _request.setHttpVersion(_version = request.getHttpVersion()); - _request.setMethod(request.getMethod()); - _request.setScheme(request.getScheme().asString()); - - HttpURI uri = request.getURI(); - - String uriHost=uri.getHost(); - if (uriHost!=null) - { - // Give precidence to authority in absolute URI - _request.setServerName(uriHost); - _request.setServerPort(uri.getPort()); - } - else - { - _request.setServerName(request.getHost()); - _request.setServerPort(request.getPort()); - } - - _request.setUri(request.getURI()); - - - String path; - try - { - path = uri.getDecodedPath(); - } - catch (Exception e) - { - LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1"); - LOG.ignore(e); - path = uri.getDecodedPath(StandardCharsets.ISO_8859_1); - } - - String info = URIUtil.canonicalPath(path); // TODO should this be done prior to decoding??? - - if (info == null) - { - if( path==null && uri.getScheme()!=null && uri.getHost()!=null) - { - info = "/"; - _request.setRequestURI(""); - } - else - throw new BadMessageException(400,"Bad URI"); - } - _request.setPathInfo(info); - - // TODO avoid playing in headers - _request.getHttpFields().addAll(request.getFields()); + _request.setMetaData(request); // TODO make this a better field for h2 hpack generation if (_configuration.getSendDateHeader()) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 7fd13dbd6a5..cbe1883de7f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -23,6 +23,8 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.AbstractMetaData; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -31,6 +33,7 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; @@ -55,6 +58,54 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl private boolean _expect = false; private boolean _expect100Continue = false; private boolean _expect102Processing = false; + private final MetaData.Request _metadata = new AbstractMetaData.Request() + { + @Override + public String getMethod() + { + return _method; + } + + @Override + public HttpScheme getScheme() + { + String scheme = _uri.getScheme(); + if (scheme==null || !scheme.endsWith("s")) + return HttpScheme.HTTP; + return HttpScheme.HTTPS; + } + + @Override + public String getHost() + { + return _hostPort==null?null:_hostPort.getHost(); + } + + @Override + public int getPort() + { + return _hostPort==null?0:_hostPort.getPort(); + } + + @Override + public HttpURI getURI() + { + return _uri; + } + + @Override + public HttpVersion getHttpVersion() + { + return _version; + } + + @Override + public HttpFields getFields() + { + return _fields; + } + + }; public HttpChannelOverHttp(HttpConnection httpConnection, Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) { @@ -295,7 +346,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl if (!persistent) _httpConnection._generator.setPersistent(false); - onRequest(new MetaData.Request(_version,_method,_uri,_fields,_hostPort)); + onRequest(_metadata); return true; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index fc1d6dcdbca..d6c6a4b378c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -60,6 +60,7 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpUpgradeHandler; import javax.servlet.http.Part; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.http.HttpField; @@ -69,6 +70,7 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler.Context; @@ -127,10 +129,10 @@ public class Request implements HttpServletRequest private static final int __NONE = 0, _STREAM = 1, __READER = 2; private final HttpChannel _channel; - private final HttpFields _fields=new HttpFields(); private final List _requestAttributeListeners=new ArrayList<>(); private final HttpInput _input; + private MetaData.Request _metadata; private boolean _secure; private boolean _asyncSupported = true; private boolean _newContext; @@ -152,7 +154,6 @@ public class Request implements HttpServletRequest private MultiMap _parameters; private String _pathInfo; private int _serverPort; - private HttpVersion _httpVersion = HttpVersion.HTTP_1_1; private String _queryEncoding; private String _queryString; private BufferedReader _reader; @@ -182,7 +183,7 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ public HttpFields getHttpFields() { - return _fields; + return _metadata.getFields(); } /* ------------------------------------------------------------ */ @@ -200,6 +201,7 @@ public class Request implements HttpServletRequest throw new IllegalArgumentException(listener.getClass().toString()); } + /* ------------------------------------------------------------ */ public void extractParameters() { if (_paramsExtracted) @@ -221,6 +223,7 @@ public class Request implements HttpServletRequest _parameters = restoreParameters(); } + /* ------------------------------------------------------------ */ private MultiMap extractQueryParameters() { MultiMap result = new MultiMap<>(); @@ -248,6 +251,7 @@ public class Request implements HttpServletRequest return result; } + /* ------------------------------------------------------------ */ private MultiMap extractContentParameters() { MultiMap result = new MultiMap<>(); @@ -276,6 +280,7 @@ public class Request implements HttpServletRequest return result; } + /* ------------------------------------------------------------ */ public void extractFormParameters(MultiMap params) { try @@ -341,6 +346,7 @@ public class Request implements HttpServletRequest } } + /* ------------------------------------------------------------ */ private void extractMultipartParameters(MultiMap result) { try @@ -480,7 +486,7 @@ public class Request implements HttpServletRequest @Override public int getContentLength() { - return (int)_fields.getLongField(HttpHeader.CONTENT_LENGTH.toString()); + return (int)_metadata.getFields().getLongField(HttpHeader.CONTENT_LENGTH.toString()); } /* ------------------------------------------------------------ */ @@ -490,7 +496,7 @@ public class Request implements HttpServletRequest @Override public long getContentLengthLong() { - return _fields.getLongField(HttpHeader.CONTENT_LENGTH.toString()); + return _metadata.getFields().getLongField(HttpHeader.CONTENT_LENGTH.toString()); } /* ------------------------------------------------------------ */ @@ -506,7 +512,7 @@ public class Request implements HttpServletRequest @Override public String getContentType() { - String content_type = _fields.getStringField(HttpHeader.CONTENT_TYPE); + String content_type = _metadata.getFields().getStringField(HttpHeader.CONTENT_TYPE); if (_characterEncoding==null && content_type!=null) { MimeTypes.Type mime = MimeTypes.CACHE.get(content_type); @@ -543,7 +549,7 @@ public class Request implements HttpServletRequest @Override public Cookie[] getCookies() { - if (_cookiesExtracted) + if (_metadata==null || _cookiesExtracted) { if (_cookies == null || _cookies.getCookies().length == 0) return null; @@ -553,7 +559,7 @@ public class Request implements HttpServletRequest _cookiesExtracted = true; - Enumeration enm = _fields.getValues(HttpHeader.COOKIE.toString()); + Enumeration enm = _metadata.getFields().getValues(HttpHeader.COOKIE.toString()); // Handle no cookies if (enm != null) @@ -582,7 +588,7 @@ public class Request implements HttpServletRequest @Override public long getDateHeader(String name) { - return _fields.getDateField(name); + return _metadata==null?-1:_metadata.getFields().getDateField(name); } /* ------------------------------------------------------------ */ @@ -599,7 +605,7 @@ public class Request implements HttpServletRequest @Override public String getHeader(String name) { - return _fields.getStringField(name); + return _metadata==null?null:_metadata.getFields().getStringField(name); } /* ------------------------------------------------------------ */ @@ -609,7 +615,9 @@ public class Request implements HttpServletRequest @Override public Enumeration getHeaderNames() { - return _fields.getFieldNames(); + if (_metadata==null) + return Collections.emptyEnumeration(); + return _metadata.getFields().getFieldNames(); } /* ------------------------------------------------------------ */ @@ -619,7 +627,9 @@ public class Request implements HttpServletRequest @Override public Enumeration getHeaders(String name) { - Enumeration e = _fields.getValues(name); + if (_metadata==null) + return Collections.emptyEnumeration(); + Enumeration e = _metadata.getFields().getValues(name); if (e == null) return Collections.enumeration(Collections.emptyList()); return e; @@ -658,7 +668,7 @@ public class Request implements HttpServletRequest @Override public int getIntHeader(String name) { - return (int)_fields.getLongField(name); + return _metadata==null?-1:(int)_metadata.getFields().getLongField(name); } @@ -669,7 +679,10 @@ public class Request implements HttpServletRequest @Override public Locale getLocale() { - Enumeration enm = _fields.getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators); + if (_metadata==null) + return Locale.getDefault(); + + Enumeration enm = _metadata.getFields().getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators); // handle no locale if (enm == null || !enm.hasMoreElements()) @@ -706,8 +719,10 @@ public class Request implements HttpServletRequest @Override public Enumeration getLocales() { - - Enumeration enm = _fields.getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators); + if (_metadata==null) + return Collections.enumeration(__defaultLocale); + + Enumeration enm = _metadata.getFields().getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators); // handle no locale if (enm == null || !enm.hasMoreElements()) @@ -907,7 +922,7 @@ public class Request implements HttpServletRequest @Override public String getProtocol() { - return _httpVersion.toString(); + return _metadata==null?null:_metadata.getHttpVersion().toString(); } /* ------------------------------------------------------------ */ @@ -916,7 +931,7 @@ public class Request implements HttpServletRequest */ public HttpVersion getHttpVersion() { - return _httpVersion; + return _metadata==null?null:_metadata.getHttpVersion(); } /* ------------------------------------------------------------ */ @@ -1181,7 +1196,7 @@ public class Request implements HttpServletRequest } // Return host from header field - HttpField host = _fields.getField(HttpHeader.HOST); + HttpField host = _metadata.getFields().getField(HttpHeader.HOST); if (host!=null) { HostPortHttpField authority = (host instanceof HostPortHttpField) @@ -1518,9 +1533,67 @@ public class Request implements HttpServletRequest return _savedNewSessions.get(key); } + + /* ------------------------------------------------------------ */ + /** + * @param request + */ + public void setMetaData(org.eclipse.jetty.http.MetaData.Request request) + { + _metadata=request; + setMethod(request.getMethod()); + setScheme(request.getScheme().asString()); + + HttpURI uri = request.getURI(); + + String uriHost=uri.getHost(); + if (uriHost!=null) + { + // Give precidence to authority in absolute URI + setServerName(uriHost); + setServerPort(uri.getPort()); + } + else + { + setServerName(request.getHost()); + setServerPort(request.getPort()); + } + + setUri(request.getURI()); + + + String path; + try + { + path = uri.getDecodedPath(); + } + catch (Exception e) + { + LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1"); + LOG.ignore(e); + path = uri.getDecodedPath(StandardCharsets.ISO_8859_1); + } + + String info = URIUtil.canonicalPath(path); // TODO should this be done prior to decoding??? + + if (info == null) + { + if( path==null && uri.getScheme()!=null && uri.getHost()!=null) + { + info = "/"; + setRequestURI(""); + } + else + throw new BadMessageException(400,"Bad URI"); + } + setPathInfo(info); + } + /* ------------------------------------------------------------ */ protected void recycle() { + _metadata=null; + if (_context != null) throw new IllegalStateException("Request in context!"); @@ -1560,7 +1633,6 @@ public class Request implements HttpServletRequest _httpMethod = null; _pathInfo = null; _serverPort = 0; - _httpVersion = HttpVersion.HTTP_1_1; _queryEncoding = null; _queryString = null; _requestedSessionId = null; @@ -1585,7 +1657,6 @@ public class Request implements HttpServletRequest _savedNewSessions=null; _multiPartInputStream = null; _remote=null; - _fields.clear(); _input.recycle(); } @@ -1728,8 +1799,7 @@ public class Request implements HttpServletRequest */ public void setContentType(String contentType) { - _fields.put(HttpHeader.CONTENT_TYPE,contentType); - + _metadata.getFields().put(HttpHeader.CONTENT_TYPE,contentType); } /* ------------------------------------------------------------ */ @@ -1818,16 +1888,6 @@ public class Request implements HttpServletRequest _pathInfo = pathInfo; } - /* ------------------------------------------------------------ */ - /** - * @param version - * The protocol to set. - */ - public void setHttpVersion(HttpVersion version) - { - _httpVersion = version; - } - /* ------------------------------------------------------------ */ /** * Set the character encoding used for the query string. This call will effect the return of getQueryString and getParamaters. It must be called before any @@ -1965,6 +2025,7 @@ public class Request implements HttpServletRequest * @param uri * The uri to set. */ + @Deprecated // is this still needed or can we use meta data? public void setUri(HttpURI uri) { _uri = uri; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 987694724ee..c69a8bd8163 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -1218,7 +1218,8 @@ public class Response implements HttpServletResponse _contentLength = -1; _fields.clear(); - String connection = _channel.getRequest().getHttpFields().getStringField(HttpHeader.CONNECTION); + String connection = _channel.getRequest().getHeader(HttpHeader.CONNECTION.asString()); + if (connection != null) { String[] values = connection.split(","); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java index db3e3617846..d1dbca78545 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java @@ -399,7 +399,6 @@ public class CrossOriginFilterTest "Origin: http://localhost\r\n" + "\r\n"; String response = tester.getResponses(request,1,TimeUnit.SECONDS); - System.err.println(response); Assert.assertTrue(response.contains("HTTP/1.1 200")); Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER)); Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER)); diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index 0bbd9e32bbe..0be51494cfb 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.spdy.server.http; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -163,7 +164,7 @@ public class HttpChannelOverSPDY extends HttpChannel // At last, add the Host header. fields.add(hostPort); - MetaData.Request request = new MetaData.Request(httpVersion, httpMethod.asString(), uri, fields, hostPort); + MetaData.Request request = new FinalMetaData.Request(httpVersion, httpMethod.asString(), uri, fields, hostPort); onRequest(request); return true; } From 4d2a580c2c8ca054841697a9d8848bdceb1c97f9 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 11 Jul 2014 17:56:08 +1000 Subject: [PATCH 140/269] 439375 preferred rfc7231 format is mime;charset=lowercase-9 --- .../org/eclipse/jetty/client/HttpRequest.java | 4 +- .../jetty/fcgi/generator/ClientGenerator.java | 3 +- .../jetty/fcgi/generator/ServerGenerator.java | 3 +- .../org/eclipse/jetty/http/HttpParser.java | 8 +- .../org/eclipse/jetty/http/MimeTypes.java | 39 ++++--- .../eclipse/jetty/http/encoding.properties | 8 +- .../eclipse/jetty/http/HttpParserTest.java | 2 +- .../org/eclipse/jetty/http/MimeTypesTest.java | 6 +- .../org/eclipse/jetty/server/Response.java | 14 +-- .../jetty/server/handler/ErrorHandler.java | 2 +- .../jetty/server/handler/ResourceHandler.java | 2 +- .../jetty/server/HttpConnectionTest.java | 2 +- .../jetty/server/HttpServerTestBase.java | 2 +- .../eclipse/jetty/server/ResponseTest.java | 100 +++++++++--------- .../eclipse/jetty/servlet/DefaultServlet.java | 4 +- .../org/eclipse/jetty/util/StringUtil.java | 40 ++----- .../org/eclipse/jetty/xml/XmlAppendable.java | 2 +- .../eclipse/jetty/xml/XmlConfiguration.java | 2 +- .../eclipse/jetty/xml/XmlAppendableTest.java | 2 +- 19 files changed, 120 insertions(+), 125 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java index dc285955578..6a5a9c66c94 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java @@ -705,7 +705,7 @@ public class HttpRequest implements Request if (value == null) return ""; - String encoding = "UTF-8"; + String encoding = "utf-8"; try { return URLEncoder.encode(value, encoding); @@ -736,7 +736,7 @@ public class HttpRequest implements Request private String urlDecode(String value) { - String charset = "UTF-8"; + String charset = "utf-8"; try { return URLDecoder.decode(value, charset); diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java index 0b07bc726d9..7f467d550ce 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.fcgi.generator; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -46,7 +47,7 @@ public class ClientGenerator extends Generator { request &= 0xFF_FF; - Charset utf8 = Charset.forName("UTF-8"); + final Charset utf8 = StandardCharsets.UTF_8; List bytes = new ArrayList<>(fields.size() * 2); int fieldsLength = 0; for (HttpField field : fields) diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java index b737f223373..e64e2e28503 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.fcgi.generator; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -54,7 +55,7 @@ public class ServerGenerator extends Generator { request &= 0xFF_FF; - Charset utf8 = Charset.forName("UTF-8"); + final Charset utf8 = StandardCharsets.UTF_8; List bytes = new ArrayList<>(fields.size() * 2); int length = 0; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 4a372729e0b..0bf87abfb3b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -186,10 +186,12 @@ public class HttpParser HttpField field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type); CACHE.put(field); - for (String charset : new String[]{"UTF-8","ISO-8859-1"}) + for (String charset : new String[]{"utf-8","iso-8859-1"}) { CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset)); CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset)); + CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset.toUpperCase())); + CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset.toUpperCase())); } } @@ -1234,7 +1236,9 @@ public class HttpParser BufferUtil.clear(buffer); Throwable cause = e.getCause(); - boolean stack = (cause instanceof RuntimeException) || (cause instanceof Error) || LOG.isDebugEnabled(); + boolean stack = LOG.isDebugEnabled() || + (!(cause instanceof NumberFormatException ) && (cause instanceof RuntimeException || cause instanceof Error)); + if (stack) LOG.warn("bad HTTP parsed: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler,e); else diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java index 9cac4abd8bc..dad35e248fc 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java @@ -56,20 +56,20 @@ public class MimeTypes TEXT_JSON("text/json",StandardCharsets.UTF_8), APPLICATION_JSON("application/json",StandardCharsets.UTF_8), - TEXT_HTML_8859_1("text/html; charset=ISO-8859-1",TEXT_HTML), - TEXT_HTML_UTF_8("text/html; charset=UTF-8",TEXT_HTML), + TEXT_HTML_8859_1("text/html;charset=iso-8859-1",TEXT_HTML), + TEXT_HTML_UTF_8("text/html;charset=utf-8",TEXT_HTML), - TEXT_PLAIN_8859_1("text/plain; charset=ISO-8859-1",TEXT_PLAIN), - TEXT_PLAIN_UTF_8("text/plain; charset=UTF-8",TEXT_PLAIN), + TEXT_PLAIN_8859_1("text/plain;charset=iso-8859-1",TEXT_PLAIN), + TEXT_PLAIN_UTF_8("text/plain;charset=utf-8",TEXT_PLAIN), - TEXT_XML_8859_1("text/xml; charset=ISO-8859-1",TEXT_XML), - TEXT_XML_UTF_8("text/xml; charset=UTF-8",TEXT_XML), + TEXT_XML_8859_1("text/xml;charset=iso-8859-1",TEXT_XML), + TEXT_XML_UTF_8("text/xml;charset=utf-8",TEXT_XML), - TEXT_JSON_8859_1("text/json; charset=ISO-8859-1",TEXT_JSON), - TEXT_JSON_UTF_8("text/json; charset=UTF-8",TEXT_JSON), + TEXT_JSON_8859_1("text/json;charset=iso-8859-1",TEXT_JSON), + TEXT_JSON_UTF_8("text/json;charset=utf-8",TEXT_JSON), - APPLICATION_JSON_8859_1("text/json; charset=ISO-8859-1",APPLICATION_JSON), - APPLICATION_JSON_UTF_8("text/json; charset=UTF-8",APPLICATION_JSON); + APPLICATION_JSON_8859_1("text/json;charset=iso-8859-1",APPLICATION_JSON), + APPLICATION_JSON_UTF_8("text/json;charset=utf-8",APPLICATION_JSON); /* ------------------------------------------------------------ */ @@ -77,6 +77,7 @@ public class MimeTypes private final Type _base; private final ByteBuffer _buffer; private final Charset _charset; + private final String _charsetString; private final boolean _assumedCharset; private final HttpField _field; @@ -87,6 +88,7 @@ public class MimeTypes _buffer=BufferUtil.toBuffer(s); _base=this; _charset=null; + _charsetString=null; _assumedCharset=false; _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string); } @@ -97,8 +99,9 @@ public class MimeTypes _string=s; _buffer=BufferUtil.toBuffer(s); _base=base; - int i=s.indexOf("; charset="); - _charset=Charset.forName(s.substring(i+10)); + int i=s.indexOf(";charset="); + _charset=Charset.forName(s.substring(i+9)); + _charsetString=_charset==null?null:_charset.toString().toLowerCase(); _assumedCharset=false; _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string); } @@ -110,6 +113,7 @@ public class MimeTypes _base=this; _buffer=BufferUtil.toBuffer(s); _charset=cs; + _charsetString=_charset==null?null:_charset.toString().toLowerCase(); _assumedCharset=true; _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string); } @@ -126,6 +130,12 @@ public class MimeTypes return _charset; } + /* ------------------------------------------------------------ */ + public String getCharsetString() + { + return _charsetString; + } + /* ------------------------------------------------------------ */ public boolean is(String s) { @@ -181,8 +191,9 @@ public class MimeTypes int charset=type.toString().indexOf(";charset="); if (charset>0) { - CACHE.put(type.toString().replace(";charset=","; charset="),type); - TYPES.put(type.toString().replace(";charset=","; charset="),type.asBuffer()); + String alt=type.toString().replace(";charset=","; charset="); + CACHE.put(alt,type); + TYPES.put(alt,type.asBuffer()); } } diff --git a/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties b/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties index 311c802190e..16d4f8ac3e2 100644 --- a/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties +++ b/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties @@ -1,4 +1,4 @@ -text/html = ISO-8859-1 -text/plain = ISO-8859-1 -text/xml = UTF-8 -text/json = UTF-8 +text/html = iso-8859-1 +text/plain = iso-8859-1 +text/xml = utf-8 +text/json = utf-8 diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 1d95e9dd391..3b328f554f2 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -1391,7 +1391,7 @@ public class HttpParserTest { ByteBuffer buffer= BufferUtil.toBuffer( "GET / HTTP/1.1\015\012" - + "Host: myhost:xxx\015\012" + + "Host: myhost:testBadPort\015\012" + "Connection: close\015\012" + "\015\012"); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java index 2ac0d463aec..67097fa1532 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java @@ -90,9 +90,9 @@ public class MimeTypesTest assertEquals("abc",MimeTypes.getCharsetFromContentType("foo/bar other = param ; charset = abc")); assertEquals("abc",MimeTypes.getCharsetFromContentType("foo/bar other = param ; charset = \"abc\" ; some=else")); assertEquals(null,MimeTypes.getCharsetFromContentType("foo/bar")); - assertEquals("UTF-8",MimeTypes.getCharsetFromContentType("foo/bar;charset=uTf8")); - assertEquals("UTF-8",MimeTypes.getCharsetFromContentType("foo/bar;other=\"charset=abc\";charset=uTf8")); - assertEquals("UTF-8",MimeTypes.getCharsetFromContentType("text/html;charset=utf-8")); + assertEquals("utf-8",MimeTypes.getCharsetFromContentType("foo/bar;charset=uTf8")); + assertEquals("utf-8",MimeTypes.getCharsetFromContentType("foo/bar;other=\"charset=abc\";charset=uTf8")); + assertEquals("utf-8",MimeTypes.getCharsetFromContentType("text/html;charset=utf-8")); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index c69a8bd8163..25dab4b4fc1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -950,7 +950,7 @@ public class Response implements HttpServletResponse if (encoding == null) { if (_mimeType!=null && _mimeType.isCharsetAssumed()) - encoding=_mimeType.getCharset().toString(); + encoding=_mimeType.getCharsetString(); else { encoding = MimeTypes.inferCharsetFromContentType(_contentType); @@ -1109,7 +1109,7 @@ public class Response implements HttpServletResponse _characterEncoding = HttpGenerator.__STRICT?encoding:StringUtil.normalizeCharset(encoding); if (_mimeType!=null) { - _contentType=_mimeType.getBaseType().asString()+ "; charset=" + _characterEncoding; + _contentType=_mimeType.getBaseType().asString()+ ";charset=" + _characterEncoding; _mimeType = MimeTypes.CACHE.get(_contentType); if (_mimeType==null || HttpGenerator.__STRICT) _fields.put(HttpHeader.CONTENT_TYPE, _contentType); @@ -1118,7 +1118,7 @@ public class Response implements HttpServletResponse } else if (_contentType != null) { - _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType) + "; charset=" + _characterEncoding; + _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType) + ";charset=" + _characterEncoding; _fields.put(HttpHeader.CONTENT_TYPE, _contentType); } } @@ -1149,7 +1149,7 @@ public class Response implements HttpServletResponse String charset; if (_mimeType!=null && _mimeType.getCharset()!=null && !_mimeType.isCharsetAssumed()) - charset=_mimeType.getCharset().toString(); + charset=_mimeType.getCharsetString(); else charset = MimeTypes.getCharsetFromContentType(contentType); @@ -1157,17 +1157,17 @@ public class Response implements HttpServletResponse { if (_characterEncoding != null) { - _contentType = contentType + "; charset=" + _characterEncoding; + _contentType = contentType + ";charset=" + _characterEncoding; _mimeType = null; } } - else if (isWriting() && !charset.equals(_characterEncoding)) + else if (isWriting() && !charset.equalsIgnoreCase(_characterEncoding)) { // too late to change the character encoding; _mimeType = null; _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType); if (_characterEncoding != null) - _contentType = _contentType + "; charset=" + _characterEncoding; + _contentType = _contentType + ";charset=" + _characterEncoding; } else { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java index b1af5208a39..0c21c1dfd18 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java @@ -140,7 +140,7 @@ public class ErrorHandler extends AbstractHandler protected void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message) throws IOException { - writer.write("\n"); + writer.write("\n"); writer.write("Error "); writer.write(Integer.toString(code)); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java index 37fda012e98..c64bb319011 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java @@ -568,7 +568,7 @@ public class ResourceHandler extends HandlerWrapper if (_directory) { String listing = resource.getListHTML(request.getRequestURI(),request.getPathInfo().lastIndexOf("/") > 0); - response.setContentType("text/html; charset=UTF-8"); + response.setContentType("text/html;charset=utf-8"); response.getWriter().println(listing); } else diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index f4b1172957c..e00ddd71df9 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -360,7 +360,7 @@ public class HttpConnectionTest "12345\015\012"+ "0;\015\012\015\012"); offset = checkContains(response,offset,"HTTP/1.1 200"); - offset = checkContains(response,offset,"encoding=ISO-8859-1"); + offset = checkContains(response,offset,"encoding=iso-8859-1"); offset = checkContains(response,offset,"/R1"); offset = checkContains(response,offset,"12345"); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java index c6c3eac0ec9..efdb8df2645 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java @@ -106,7 +106,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture + "</nimbus>\n"; protected static final String RESPONSE2 = "HTTP/1.1 200 OK\n" + - "Content-Type: text/xml; charset=ISO-8859-1\n" + + "Content-Type: text/xml;charset=iso-8859-1\n" + "Content-Length: " + RESPONSE2_CONTENT.getBytes().length + "\n" + "Server: Jetty(" + Server.getVersion() + ")\n" + "\n" + diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 3513fe98e0e..82c5321dc4e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -129,9 +129,9 @@ public class ResponseTest response.setContentType("foo/bar"); assertEquals("foo/bar", response.getContentType()); response.getWriter(); - assertEquals("foo/bar; charset=ISO-8859-1", response.getContentType()); + assertEquals("foo/bar;charset=iso-8859-1", response.getContentType()); response.setContentType("foo2/bar2"); - assertEquals("foo2/bar2; charset=ISO-8859-1", response.getContentType()); + assertEquals("foo2/bar2;charset=iso-8859-1", response.getContentType()); response.setHeader("name", "foo"); Iterator<String> en = response.getHeaders("name").iterator(); @@ -148,16 +148,16 @@ public class ResponseTest response.setContentType("text/html"); assertEquals("text/html", response.getContentType()); response.getWriter(); - assertEquals("text/html; charset=ISO-8859-1", response.getContentType()); + assertEquals("text/html;charset=iso-8859-1", response.getContentType()); response.setContentType("foo2/bar2"); - assertEquals("foo2/bar2; charset=ISO-8859-1", response.getContentType()); + assertEquals("foo2/bar2;charset=iso-8859-1", response.getContentType()); response.recycle(); response.setContentType("text/xml;charset=ISO-8859-7"); response.getWriter(); assertEquals("text/xml;charset=ISO-8859-7", response.getContentType()); response.setContentType("text/html;charset=UTF-8"); - assertEquals("text/html; charset=ISO-8859-7", response.getContentType()); + assertEquals("text/html;charset=ISO-8859-7", response.getContentType()); response.recycle(); response.setContentType("text/html;charset=US-ASCII"); @@ -165,9 +165,9 @@ public class ResponseTest assertEquals("text/html;charset=US-ASCII", response.getContentType()); response.recycle(); - response.setContentType("text/html; charset=utf-8"); + response.setContentType("text/html; charset=UTF-8"); response.getWriter(); - assertEquals("text/html; charset=UTF-8", response.getContentType()); + assertEquals("text/html;charset=utf-8", response.getContentType()); response.recycle(); response.setContentType("text/json"); @@ -178,17 +178,17 @@ public class ResponseTest response.setContentType("text/json"); response.setCharacterEncoding("UTF-8"); response.getWriter(); - assertEquals("text/json; charset=UTF-8", response.getContentType()); + assertEquals("text/json;charset=utf-8", response.getContentType()); response.recycle(); response.setCharacterEncoding("xyz"); response.setContentType("foo/bar"); - assertEquals("foo/bar; charset=xyz", response.getContentType()); + assertEquals("foo/bar;charset=xyz", response.getContentType()); response.recycle(); response.setContentType("foo/bar"); response.setCharacterEncoding("xyz"); - assertEquals("foo/bar; charset=xyz", response.getContentType()); + assertEquals("foo/bar;charset=xyz", response.getContentType()); response.recycle(); response.setCharacterEncoding("xyz"); @@ -198,7 +198,7 @@ public class ResponseTest response.recycle(); response.setContentType("foo/bar;charset=abc"); response.setCharacterEncoding("xyz"); - assertEquals("foo/bar; charset=xyz", response.getContentType()); + assertEquals("foo/bar;charset=xyz", response.getContentType()); response.recycle(); response.setCharacterEncoding("xyz"); @@ -235,14 +235,14 @@ public class ResponseTest response.setLocale(java.util.Locale.ITALIAN); assertEquals(null, response.getContentType()); response.setContentType("text/plain"); - assertEquals("text/plain; charset=ISO-8859-2", response.getContentType()); + assertEquals("text/plain;charset=ISO-8859-2", response.getContentType()); response.recycle(); response.setContentType("text/plain"); response.setCharacterEncoding("utf-8"); response.setLocale(java.util.Locale.ITALIAN); - assertEquals("text/plain; charset=UTF-8", response.getContentType()); - assertTrue(response.toString().indexOf("charset=UTF-8") > 0); + assertEquals("text/plain;charset=utf-8", response.getContentType()); + assertTrue(response.toString().indexOf("charset=utf-8") > 0); } @Test @@ -252,25 +252,25 @@ public class ResponseTest response.setContentType("foo/bar"); response.setCharacterEncoding("utf-8"); - assertEquals("foo/bar; charset=UTF-8", response.getContentType()); + assertEquals("foo/bar;charset=utf-8", response.getContentType()); response.getWriter(); - assertEquals("foo/bar; charset=UTF-8", response.getContentType()); + assertEquals("foo/bar;charset=utf-8", response.getContentType()); response.setContentType("foo2/bar2"); - assertEquals("foo2/bar2; charset=UTF-8", response.getContentType()); + assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); response.setCharacterEncoding("ISO-8859-1"); - assertEquals("foo2/bar2; charset=UTF-8", response.getContentType()); + assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); response.recycle(); response.setContentType("text/html"); - response.setCharacterEncoding("utf-8"); - assertEquals("text/html; charset=UTF-8", response.getContentType()); + response.setCharacterEncoding("UTF-8"); + assertEquals("text/html;charset=utf-8", response.getContentType()); response.getWriter(); - assertEquals("text/html; charset=UTF-8", response.getContentType()); + assertEquals("text/html;charset=utf-8", response.getContentType()); response.setContentType("text/xml"); - assertEquals("text/xml; charset=UTF-8", response.getContentType()); + assertEquals("text/xml;charset=utf-8", response.getContentType()); response.setCharacterEncoding("ISO-8859-1"); - assertEquals("text/xml; charset=UTF-8", response.getContentType()); + assertEquals("text/xml;charset=utf-8", response.getContentType()); } @Test @@ -279,25 +279,25 @@ public class ResponseTest Response response = newResponse(); response.setCharacterEncoding("utf-8"); response.setContentType("foo/bar"); - assertEquals("foo/bar; charset=UTF-8", response.getContentType()); + assertEquals("foo/bar;charset=utf-8", response.getContentType()); response.getWriter(); - assertEquals("foo/bar; charset=UTF-8", response.getContentType()); + assertEquals("foo/bar;charset=utf-8", response.getContentType()); response.setContentType("foo2/bar2"); - assertEquals("foo2/bar2; charset=UTF-8", response.getContentType()); + assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); response.setCharacterEncoding("ISO-8859-1"); - assertEquals("foo2/bar2; charset=UTF-8", response.getContentType()); + assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); response.recycle(); response.setCharacterEncoding("utf-8"); response.setContentType("text/html"); - assertEquals("text/html; charset=UTF-8", response.getContentType()); + assertEquals("text/html;charset=utf-8", response.getContentType()); response.getWriter(); - assertEquals("text/html; charset=UTF-8", response.getContentType()); + assertEquals("text/html;charset=utf-8", response.getContentType()); response.setContentType("text/xml"); - assertEquals("text/xml; charset=UTF-8", response.getContentType()); + assertEquals("text/xml;charset=utf-8", response.getContentType()); response.setCharacterEncoding("iso-8859-1"); - assertEquals("text/xml; charset=UTF-8", response.getContentType()); + assertEquals("text/xml;charset=utf-8", response.getContentType()); } @Test @@ -306,26 +306,26 @@ public class ResponseTest Response response = newResponse(); response.setCharacterEncoding("utf16"); - response.setContentType("foo/bar; charset=utf-8"); - assertEquals("foo/bar; charset=utf-8", response.getContentType()); + response.setContentType("foo/bar; charset=UTF-8"); + assertEquals("foo/bar; charset=UTF-8", response.getContentType()); response.getWriter(); - assertEquals("foo/bar; charset=utf-8", response.getContentType()); + assertEquals("foo/bar; charset=UTF-8", response.getContentType()); response.setContentType("foo2/bar2"); - assertEquals("foo2/bar2; charset=UTF-8", response.getContentType()); + assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); response.setCharacterEncoding("ISO-8859-1"); - assertEquals("foo2/bar2; charset=UTF-8", response.getContentType()); + assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); response.recycle(); response.setCharacterEncoding("utf16"); response.setContentType("text/html; charset=utf-8"); - assertEquals("text/html; charset=UTF-8", response.getContentType()); + assertEquals("text/html;charset=utf-8", response.getContentType()); response.getWriter(); - assertEquals("text/html; charset=UTF-8", response.getContentType()); + assertEquals("text/html;charset=utf-8", response.getContentType()); response.setContentType("text/xml"); - assertEquals("text/xml; charset=UTF-8", response.getContentType()); + assertEquals("text/xml;charset=utf-8", response.getContentType()); response.setCharacterEncoding("iso-8859-1"); - assertEquals("text/xml; charset=UTF-8", response.getContentType()); + assertEquals("text/xml;charset=utf-8", response.getContentType()); } @Test @@ -336,19 +336,19 @@ public class ResponseTest response.setContentType("foo/bar; other=xyz"); assertEquals("foo/bar; other=xyz", response.getContentType()); response.getWriter(); - assertEquals("foo/bar; other=xyz; charset=ISO-8859-1", response.getContentType()); + assertEquals("foo/bar; other=xyz;charset=iso-8859-1", response.getContentType()); response.setContentType("foo2/bar2"); - assertEquals("foo2/bar2; charset=ISO-8859-1", response.getContentType()); + assertEquals("foo2/bar2;charset=iso-8859-1", response.getContentType()); response.recycle(); - response.setCharacterEncoding("utf-8"); + response.setCharacterEncoding("uTf-8"); response.setContentType("text/html; other=xyz"); - assertEquals("text/html; other=xyz; charset=UTF-8", response.getContentType()); + assertEquals("text/html; other=xyz;charset=utf-8", response.getContentType()); response.getWriter(); - assertEquals("text/html; other=xyz; charset=UTF-8", response.getContentType()); + assertEquals("text/html; other=xyz;charset=utf-8", response.getContentType()); response.setContentType("text/xml"); - assertEquals("text/xml; charset=UTF-8", response.getContentType()); + assertEquals("text/xml;charset=utf-8", response.getContentType()); } @Test @@ -366,17 +366,17 @@ public class ResponseTest response.setCharacterEncoding("utf16"); response.setContentType("text/html; other=xyz charset=utf-8"); - assertEquals("text/html; other=xyz charset=utf-8; charset=UTF-16", response.getContentType()); + assertEquals("text/html; other=xyz charset=utf-8;charset=utf-16", response.getContentType()); response.getWriter(); - assertEquals("text/html; other=xyz charset=utf-8; charset=UTF-16", response.getContentType()); + assertEquals("text/html; other=xyz charset=utf-8;charset=utf-16", response.getContentType()); response.recycle(); response.setCharacterEncoding("utf16"); response.setContentType("foo/bar; other=pq charset=utf-8 other=xyz"); - assertEquals("foo/bar; other=pq charset=utf-8 other=xyz; charset=UTF-16", response.getContentType()); + assertEquals("foo/bar; other=pq charset=utf-8 other=xyz;charset=utf-16", response.getContentType()); response.getWriter(); - assertEquals("foo/bar; other=pq charset=utf-8 other=xyz; charset=UTF-16", response.getContentType()); + assertEquals("foo/bar; other=pq charset=utf-8 other=xyz;charset=utf-16", response.getContentType()); } @Test diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java index ed5d330f7e8..3019e532466 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java @@ -847,8 +847,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory return; } - data=dir.getBytes("UTF-8"); - response.setContentType("text/html; charset=UTF-8"); + data=dir.getBytes("utf-8"); + response.setContentType("text/html;charset=utf-8"); response.setContentLength(data.length); response.getOutputStream().write(data); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java index cd0e7da27ed..76de31b4f82 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.util; import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import org.eclipse.jetty.util.log.Log; @@ -46,39 +45,18 @@ public class StringUtil public static final String __LINE_SEPARATOR= System.getProperty("line.separator","\n"); - public static final String __ISO_8859_1="ISO-8859-1"; - public final static String __UTF8="UTF-8"; - public final static String __UTF16="UTF-16"; - - /** - * @deprecated Use {@link StandardCharsets#UTF_8} - */ - @Deprecated - public final static Charset __UTF8_CHARSET=StandardCharsets.UTF_8; - /** - * @deprecated Use {@link StandardCharsets#ISO_8859_1} - */ - @Deprecated - public final static Charset __ISO_8859_1_CHARSET=StandardCharsets.ISO_8859_1; - /** - * @deprecated Use {@link StandardCharsets#UTF_16} - */ - @Deprecated - public final static Charset __UTF16_CHARSET=StandardCharsets.UTF_16; - /** - * @deprecated Use {@link StandardCharsets#US_ASCII} - */ - @Deprecated - public final static Charset __US_ASCII_CHARSET=StandardCharsets.US_ASCII; + public static final String __ISO_8859_1="iso-8859-1"; + public final static String __UTF8="utf-8"; + public final static String __UTF16="utf-16"; static { - CHARSETS.put("UTF-8",__UTF8); - CHARSETS.put("UTF8",__UTF8); - CHARSETS.put("UTF-16",__UTF16); - CHARSETS.put("UTF16",__UTF16); - CHARSETS.put("ISO-8859-1",__ISO_8859_1); - CHARSETS.put("ISO_8859_1",__ISO_8859_1); + CHARSETS.put("utf-8",__UTF8); + CHARSETS.put("utf8",__UTF8); + CHARSETS.put("utf-16",__UTF16); + CHARSETS.put("utf16",__UTF16); + CHARSETS.put("iso-8859-1",__ISO_8859_1); + CHARSETS.put("iso_8859_1",__ISO_8859_1); } /* ------------------------------------------------------------ */ diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java index 64270af3473..26e84904ce2 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java @@ -50,7 +50,7 @@ public class XmlAppendable public XmlAppendable(Appendable out, int indent) throws IOException { - this(out,indent,"UTF-8"); + this(out,indent,"utf-8"); } public XmlAppendable(Appendable out, int indent, String encoding) throws IOException diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index 18d85eb20f0..3b88bdc8935 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -150,7 +150,7 @@ public class XmlConfiguration */ public XmlConfiguration(String configuration) throws SAXException, IOException { - configuration = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"http://eclipse.org/jetty/configure.dtd\">" + configuration = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"http://eclipse.org/jetty/configure.dtd\">" + configuration; InputSource source = new InputSource(new StringReader(configuration)); synchronized (__parser) diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java index 0e491f6b74f..938ecd59288 100644 --- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java +++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java @@ -49,7 +49,7 @@ public class XmlAppendableTest out.closeTag(); String expected = "" + - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<test>\n" + " <tag/>\n" + " <tag name=\"attr value\" noval=\"\" quotes=\"'"\"/>\n" + From 3bbd1dae59e1bdcca6c55ff95258a1aa679c6c29 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 16 Jul 2014 16:40:12 +1000 Subject: [PATCH 141/269] fixed merge --- .../src/test/java/org/eclipse/jetty/server/RequestTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index e985eee97e0..18811c52900 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -367,10 +367,10 @@ public class RequestTest assertEquals(null,results.get(i++)); assertEquals("text/html;charset=utf8",results.get(i++)); - assertEquals("UTF-8",results.get(i++)); + assertEquals("utf-8",results.get(i++)); assertEquals("text/html; charset=\"utf8\"",results.get(i++)); - assertEquals("UTF-8",results.get(i++)); + assertEquals("utf-8",results.get(i++)); assertTrue(results.get(i++).startsWith("text/html")); assertEquals(" x=z; ",results.get(i++)); From 89a816843f009752fe544e44f222d4b9801f0bfd Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 16 Jul 2014 14:04:08 +1000 Subject: [PATCH 142/269] removed refset from hpack --- jetty-http2/http2-hpack/pom.xml | 6 + .../jetty/http2/hpack/HpackContext.java | 204 +- .../jetty/http2/hpack/HpackDecoder.java | 22 +- .../jetty/http2/hpack/HpackEncoder.java | 63 +- .../jetty/http2/hpack/HpackContextTest.java | 361 +- .../jetty/http2/hpack/HpackDecoderTest.java | 3 + .../jetty/http2/hpack/HpackEncoderTest.java | 85 +- .../jetty/http2/hpack/HpackPerfTest.java | 133 + .../src/test/resources/data/story_00.json | 53 + .../src/test/resources/data/story_01.json | 52 + .../src/test/resources/data/story_02.json | 339 + .../src/test/resources/data/story_03.json | 342 + .../src/test/resources/data/story_04.json | 342 + .../src/test/resources/data/story_05.json | 366 + .../src/test/resources/data/story_06.json | 342 + .../src/test/resources/data/story_07.json | 345 + .../src/test/resources/data/story_08.json | 363 + .../src/test/resources/data/story_09.json | 345 + .../src/test/resources/data/story_10.json | 339 + .../src/test/resources/data/story_11.json | 369 + .../src/test/resources/data/story_12.json | 369 + .../src/test/resources/data/story_13.json | 342 + .../src/test/resources/data/story_14.json | 339 + .../src/test/resources/data/story_15.json | 336 + .../src/test/resources/data/story_16.json | 375 + .../src/test/resources/data/story_17.json | 348 + .../src/test/resources/data/story_18.json | 351 + .../src/test/resources/data/story_19.json | 345 + .../src/test/resources/data/story_20.json | 5674 ++++ .../src/test/resources/data/story_21.json | 15422 +++++++++ .../src/test/resources/data/story_22.json | 14947 ++++++++ .../src/test/resources/data/story_23.json | 13406 ++++++++ .../src/test/resources/data/story_24.json | 1187 + .../src/test/resources/data/story_25.json | 8637 +++++ .../src/test/resources/data/story_26.json | 4439 +++ .../src/test/resources/data/story_27.json | 9890 ++++++ .../src/test/resources/data/story_28.json | 5293 +++ .../src/test/resources/data/story_29.json | 13780 ++++++++ .../src/test/resources/data/story_30.json | 28257 ++++++++++++++++ .../src/test/resources/data/story_31.json | 4555 +++ .../test/resources/jetty-logging.properties | 2 +- .../org/eclipse/jetty/util/ArrayQueue.java | 4 +- 42 files changed, 132129 insertions(+), 643 deletions(-) create mode 100644 jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_00.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_01.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_02.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_03.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_04.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_05.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_06.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_07.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_08.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_09.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_10.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_11.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_12.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_13.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_14.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_15.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_16.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_17.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_18.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_19.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_20.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_21.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_22.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_23.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_24.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_25.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_26.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_27.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_28.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_29.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_30.json create mode 100644 jetty-http2/http2-hpack/src/test/resources/data/story_31.json diff --git a/jetty-http2/http2-hpack/pom.xml b/jetty-http2/http2-hpack/pom.xml index 8b7a7fe8f1c..0ae0e947ac0 100644 --- a/jetty-http2/http2-hpack/pom.xml +++ b/jetty-http2/http2-hpack/pom.xml @@ -31,6 +31,12 @@ <artifactId>jetty-test-helper</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util-ajax</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 21f16ec73e6..68f7f9882b8 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -21,9 +21,7 @@ package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Set; import org.eclipse.jetty.http.HttpField; @@ -167,18 +165,9 @@ public class HpackContext private int _maxHeaderTableSizeInBytes; private int _headerTableSizeInBytes; - private final Entry _refSet=new Entry(); private final HeaderTable _headerTable; private final Map<HttpField,Entry> _fieldMap = new HashMap<>(); private final Map<String,Entry> _nameMap = new HashMap<>(); - private Iterable<Entry> referenceSet = new Iterable<Entry>() - { - @Override - public Iterator<Entry> iterator() - { - return iterateReferenceSet(); - } - }; HpackContext(int maxHeaderTableSize) { @@ -217,21 +206,20 @@ public class HpackContext public Entry get(int index) { - index=index-_headerTable.size(); - if (index>0) - { - if (index>=__staticTable.length) - return null; + if (index<__staticTable.length) return __staticTable[index]; - } - - return _headerTable.getUnsafe(-index); + + int d=_headerTable.size()-index+__staticTable.length-1; + + if (d>=0) + return _headerTable.getUnsafe(d); + return null; } public Entry add(HttpField field) { - int i=_headerTable.getNextIndexUnsafe(); - Entry entry=new Entry(i,field); + int slot=_headerTable.getNextSlotUnsafe(); + Entry entry=new Entry(slot,field); int size = entry.getSize(); if (size>_maxHeaderTableSizeInBytes) { @@ -276,109 +264,12 @@ public class HpackContext public int index(Entry entry) { - if (entry._index<0) + if (entry._slot<0) return 0; if (entry.isStatic()) - return _headerTable.size() + entry._index; - return _headerTable.index(entry); - } - - public void addToRefSet(Entry entry) - { - entry.addToRefSet(this); - } - - public Iterable<Entry> getReferenceSet() - { - return referenceSet; - } - - public void clearReferenceSet() - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("RefSet[%x] cleared",hashCode())); - Entry entry = _refSet._refSetNext; - while(entry!=_refSet) - { - Entry next = entry._refSetNext; - entry.removeFromRefSet(); - entry=next; - } - } - + return entry._slot; - public void removedUnusedReferences(ByteBuffer buffer) - { - Entry entry = _refSet._refSetNext; - while(entry!=_refSet) - { - Entry next = entry._refSetNext; - - if (entry.isUsed()) - entry._used=false; - else - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("RefSet[%x] remove unused %s",hashCode(),entry)); - // encode the reference to remove it - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,index(entry)); - entry.removeFromRefSet(); - } - entry=next; - } - } - - public void emitUnusedReferences(MetaDataBuilder builder) - { - Entry entry = _refSet._refSetNext; - while(entry!=_refSet) - { - if (entry.isUsed()) - entry._used=false; - else - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("RefSet[%x] emit unref %s",hashCode(),entry)); - builder.emit(entry.getHttpField()); - } - - entry=entry._refSetNext; - } - } - - - public Iterator<Entry> iterateReferenceSet() - { - return new Iterator<Entry>() - { - Entry _next = _refSet._refSetNext; - - @Override - public boolean hasNext() - { - return _next!=_refSet; - } - - @Override - public Entry next() - { - if (_next==_refSet) - throw new NoSuchElementException(); - Entry next=_next; - _next=_next._refSetNext; - return next; - } - - @Override - public void remove() - { - if (_next._refSetPrev==_refSet) - throw new NoSuchElementException(); - - _next._refSetPrev.removeFromRefSet(); - } - }; + return _headerTable.index(entry)+__staticTable.length-1; } private void evict() @@ -389,8 +280,7 @@ public class HpackContext if (LOG.isDebugEnabled()) LOG.debug(String.format("HdrTbl[%x] evict %s",hashCode(),entry)); _headerTableSizeInBytes-=entry.getSize(); - entry.removeFromRefSet(); - entry._index=-1; + entry._slot=-1; _fieldMap.remove(entry.getHttpField()); String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName()); if (entry==_nameMap.get(lc)) @@ -425,8 +315,8 @@ public class HpackContext { // Relay on super.growUnsafe to pack all entries 0 to _nextSlot super.resizeUnsafe(newCapacity); - for (int i=0;i<_nextSlot;i++) - ((Entry)_elements[i])._index=i; + for (int s=0;s<_nextSlot;s++) + ((Entry)_elements[s])._slot=s; } /* ------------------------------------------------------------ */ @@ -456,7 +346,7 @@ public class HpackContext */ private int index(Entry entry) { - return entry._index>=_nextE?_size-entry._index+_nextE:_nextSlot-entry._index; + return entry._slot>=_nextE?_size-entry._slot+_nextE:_nextSlot-entry._slot; } } @@ -469,65 +359,25 @@ public class HpackContext public static class Entry { final HttpField _field; - int _index; - Entry _refSetNext=this; - Entry _refSetPrev=this; - boolean _used; + int _slot; Entry() { - _index=0; + _slot=0; _field=null; } Entry(int index,String name, String value) { - _index=index; + _slot=index; _field=new HttpField(name,value); } - Entry(int index, HttpField field) + Entry(int slot, HttpField field) { - _index=index; + _slot=slot; _field=field; } - - private void addToRefSet(HpackContext ctx) - { - if (isStatic()) - throw new IllegalStateException("static"); - if (_index<0) - throw new IllegalStateException("evicted"); - if (_refSetNext!=this) - return; - - _used=true; - _refSetNext=ctx._refSet; - _refSetPrev=ctx._refSet._refSetPrev; - ctx._refSet._refSetPrev._refSetNext=this; - ctx._refSet._refSetPrev=this; - if (LOG.isDebugEnabled()) - LOG.debug(String.format("RefSet[%x] added",ctx.hashCode(),this)); - } - - public boolean isInReferenceSet() - { - return _refSetNext!=this; - } - - public void removeFromRefSet() - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("RefSet[?] remove %s",this)); - if (_refSetNext!=this) - { - _refSetNext._refSetPrev=_refSetPrev; - _refSetPrev._refSetNext=_refSetNext; - _refSetNext=this; - _refSetPrev=this; - _used=false; - } - } public int getSize() { @@ -551,17 +401,7 @@ public class HpackContext public String toString() { - return String.format("{%s,%d,%s,%x}",isStatic()?"S":"D",_index,_field,hashCode()); - } - - public void used() - { - _used=true; - } - - public boolean isUsed() - { - return _used; + return String.format("{%s,%d,%s,%x}",isStatic()?"S":"D",_slot,_field,hashCode()); } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 82efe316c36..0a172a22964 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -83,19 +83,15 @@ public class HpackDecoder // indexed int index = NBitInteger.decode(buffer,7); Entry entry=_context.get(index); - if (entry.isInReferenceSet()) - _context.get(index).removeFromRefSet(); - else if (entry.isStatic()) + if (entry.isStatic()) { if (LOG.isDebugEnabled()) LOG.debug("decode IdxStatic {}",entry); // emit field _builder.emit(entry.getHttpField()); - // copy and add to reference set if there is room - Entry new_entry = _context.add(entry.getHttpField()); - if (new_entry!=null) - _context.addToRefSet(new_entry); + // TODO copy and add to reference set if there is room + // _context.add(entry.getHttpField()); } else { @@ -103,8 +99,6 @@ public class HpackDecoder LOG.debug("decode Idx {}",entry); // emit _builder.emit(entry.getHttpField()); - // add to reference set - _context.addToRefSet(entry); } } else @@ -210,10 +204,7 @@ public class HpackDecoder if (indexed) { // add to header table - Entry new_entry=_context.add(field); - // and to ref set if there was room in header table - if (new_entry!=null) - _context.addToRefSet(new_entry); + _context.add(field); } } else if (f==2) @@ -228,15 +219,12 @@ public class HpackDecoder } else if (f==3) { - // clear reference set if (LOG.isDebugEnabled()) - LOG.debug("decode clear"); - _context.clearReferenceSet(); + LOG.debug("unused"); } } } - _context.emitUnusedReferences(_builder); return _builder.build(); } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 445e55370b6..df7d7f98beb 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -161,7 +161,6 @@ public class HpackEncoder encode(buffer,field); } - _context.removedUnusedReferences(buffer); } public void encodeMaxHeaderTableSize(ByteBuffer buffer, int maxHeaderTableSize) @@ -173,12 +172,6 @@ public class HpackEncoder _context.resize(maxHeaderTableSize); } - public void encodeClearReferenceSet(ByteBuffer buffer) - { - buffer.put((byte)0x30); - _context.clearReferenceSet(); - } - private void encode(ByteBuffer buffer, HttpField field) { final int p=LOG.isDebugEnabled()?buffer.position():-1; @@ -192,49 +185,18 @@ public class HpackEncoder if (entry!=null) { - // if entry is already in the reference set, then nothing more to do. - if (entry.isInReferenceSet()) - { - entry.used(); - encoding="InRefSet"; - } - // Is this as static field - else if (entry.isStatic()) + if (entry.isStatic()) { - // TODO Strategy decision to make! - // Should we add to reference set or just always send as indexed? + // entries like :status: 200 and :method: GET are worthwhile putting into ref set. + // as they are likely to be repeated. + encoding="StaticIndexed"; + int index=_context.index(entry); + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,index); - if (((StaticEntry)entry).useRefSet()) - { - // entries like :status: 200 and :method: GET are worthwhile putting into ref set. - // as they are likely to be repeated. - encoding="StaticIndexed"; - int index=_context.index(entry); - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,index); - entry=_context.add(entry.getHttpField()); - if (entry!=null) - _context.addToRefSet(entry); - } - else - { - // Let's send other statics as indexed to reduce churn in header table! - // BUGGER! Can't do that as we have to copy them into header table. - // Oh well all the static fields have small values, so - // lets send as literal header, indexed name. - // We don't need never indexed because the cookie fields are name only and we can - // huffman encode the value for the same reason. - - // Add the token - buffer.put((byte)0x00); - // Add the name index - NBitInteger.encode(buffer,4,_context.index(entry)); - // Add the value - buffer.put(entry.getStaticHuffmanValue()); - - encoding="LiteralStaticIdxNameHuffmanValue"; - } + // TODO Copy? + // entry=_context.add(entry.getHttpField()); } else { @@ -244,7 +206,6 @@ public class HpackEncoder int index=_context.index(entry); buffer.put((byte)0x80); NBitInteger.encode(buffer,7,index); - _context.addToRefSet(entry); } } else @@ -335,11 +296,7 @@ public class HpackEncoder // If we want the field referenced, then we add it to our // table and reference set. if (reference) - { - Entry new_entry=_context.add(field); - if (new_entry!=null) - _context.addToRefSet(new_entry); - } + _context.add(field); } if (p>=0) diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java index 46a5cdc7803..2f4c488eac9 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java @@ -215,26 +215,26 @@ public class HpackContextTest // Add a single entry entry[0]=ctx.add(field[0]); - // Check new entry is 1 + // Check new entry is 62 assertEquals(1,ctx.size()); - assertEquals(1,ctx.index(entry[0])); - assertEquals(entry[0],ctx.get(1)); + assertEquals(62,ctx.index(entry[0])); + assertEquals(entry[0],ctx.get(62)); - // and statics have moved up 1 - assertEquals(":authority",ctx.get(1+1).getHttpField().getName()); - assertEquals(3+1,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3+1).getHttpField()); - assertEquals("www-authenticate",ctx.get(61+1).getHttpField().getName()); - assertEquals(null,ctx.get(62+1)); + // and statics have moved up 0 + assertEquals(":authority",ctx.get(1+0).getHttpField().getName()); + assertEquals(3+0,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+0).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName()); + assertEquals(null,ctx.get(62+0+ctx.size())); // Add 4 more entries for (int i=1;i<=4;i++) entry[i]=ctx.add(field[i]); - // Check newest entry is at 1 oldest at 5 + // Check newest entry is at 62 oldest at 66 assertEquals(5,ctx.size()); - int index=5; + int index=66; for (int i=0;i<=4;i++) { assertEquals(index,ctx.index(entry[i])); @@ -242,18 +242,18 @@ public class HpackContextTest index--; } - // and statics have moved up 5 - assertEquals(":authority",ctx.get(1+5).getHttpField().getName()); - assertEquals(3+5,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3+5).getHttpField()); - assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName()); - assertEquals(null,ctx.get(62+5)); + // and statics have moved up 0 + assertEquals(":authority",ctx.get(1+0).getHttpField().getName()); + assertEquals(3+0,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+0).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName()); + assertEquals(null,ctx.get(62+0+ctx.size())); // add 1 more entry and this should cause an eviction! entry[5]=ctx.add(field[5]); // Check newest entry is at 1 oldest at 5 - index=5; + index=66; for (int i=1;i<=5;i++) { assertEquals(index,ctx.index(entry[i])); @@ -264,19 +264,19 @@ public class HpackContextTest assertNull(ctx.get(field[0])); assertEquals(0,ctx.index(entry[0])); - // and statics have moved up just 5 - assertEquals(":authority",ctx.get(1+5).getHttpField().getName()); - assertEquals(3+5,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3+5).getHttpField()); - assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName()); - assertEquals(null,ctx.get(62+5)); + // and statics have moved up 0 + assertEquals(":authority",ctx.get(1+0).getHttpField().getName()); + assertEquals(3+0,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+0).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName()); + assertEquals(null,ctx.get(62+0+ctx.size())); // Add 4 more entries for (int i=6;i<=9;i++) entry[i]=ctx.add(field[i]); // Check newest entry is at 1 oldest at 5 - index=5; + index=66; for (int i=5;i<=9;i++) { assertEquals(index,ctx.index(entry[i])); @@ -295,7 +295,7 @@ public class HpackContextTest for (int i=10;i<=52;i++) entry[i]=ctx.add(new HttpField("n"+i,"v"+i)); - index=5; + index=66; for (int i=48;i<=52;i++) { assertEquals(index,ctx.index(entry[i])); @@ -304,210 +304,6 @@ public class HpackContextTest } } - - @Test - public void testRefSetAddStatic() - { - try - { - HpackContext ctx = new HpackContext(4096); - - HttpField methodGet = new HttpField(":method","GET"); - Entry entry = ctx.get(methodGet); - ctx.addToRefSet(entry); - fail(); - } - catch(IllegalStateException e) - {} - } - - @Test - public void testRefSetAddEvicted() - { - try - { - HpackContext ctx = new HpackContext(38); - HttpField field0 = new HttpField("foo","bar"); - HttpField field1 = new HttpField("xxx","yyy"); - Entry entry = ctx.add(field0); - ctx.add(field1); - ctx.addToRefSet(entry); - fail(); - } - catch(IllegalStateException e) - {} - } - - @Test - public void testRefSetEmptyIteration() - { - HpackContext ctx = new HpackContext(4096); - for (Entry entry: ctx.getReferenceSet() ) - fail("unexpected:"+entry); - Iterator<Entry> iter = ctx.iterateReferenceSet(); - assertFalse(iter.hasNext()); - - try - { - iter.next(); - fail(); - } - catch(NoSuchElementException e) - { - } - - try - { - iter.remove(); - fail(); - } - catch(NoSuchElementException e) - { - } - - } - - - @Test - public void testRefSet() - { - // Only enough space for 5 entries - HpackContext ctx = new HpackContext(38*5); - - HttpField[] field = - { - new HttpField("fo0","b0r"), - new HttpField("fo1","b1r"), - new HttpField("fo2","b2r"), - new HttpField("fo3","b3r"), - new HttpField("fo4","b4r"), - new HttpField("fo5","b5r"), - new HttpField("fo6","b6r"), - new HttpField("fo7","b7r"), - new HttpField("fo8","b8r"), - new HttpField("fo9","b9r"), - new HttpField("foA","bAr"), - }; - Entry[] entry = new Entry[field.length]; - - // Add 5 entries - for (int i=0;i<=4;i++) - entry[i]=ctx.add(field[i]); - - // Add 3 entries to reference set - ctx.addToRefSet(ctx.get(3)); - ctx.addToRefSet(ctx.get(1)); - ctx.addToRefSet(ctx.get(5)); - - // check isInReferenceSet - assertTrue(ctx.get(1).isInReferenceSet()); - assertFalse(ctx.get(2).isInReferenceSet()); - assertTrue(ctx.get(3).isInReferenceSet()); - assertFalse(ctx.get(4).isInReferenceSet()); - assertTrue(ctx.get(5).isInReferenceSet()); - - // iterate ref set - HashSet<HttpField> fields = new HashSet<>(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(3,fields.size()); - assertTrue(fields.contains(field[0])); - assertTrue(fields.contains(field[2])); - assertTrue(fields.contains(field[4])); - - // duplicate add ignored - ctx.addToRefSet(ctx.get(1)); - fields.clear(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(3,fields.size()); - assertTrue(fields.contains(field[0])); - assertTrue(fields.contains(field[2])); - assertTrue(fields.contains(field[4])); - - // remove entry - ctx.get(3).removeFromRefSet(); - fields.clear(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(2,fields.size()); - assertTrue(fields.contains(field[0])); - assertTrue(fields.contains(field[4])); - - // check isInReferenceSet - assertTrue(ctx.get(1).isInReferenceSet()); - assertFalse(ctx.get(2).isInReferenceSet()); - assertFalse(ctx.get(3).isInReferenceSet()); - assertFalse(ctx.get(4).isInReferenceSet()); - assertTrue(ctx.get(5).isInReferenceSet()); - - // iterator remove - Iterator<Entry> iter=ctx.iterateReferenceSet(); - iter.next(); - iter.remove(); - fields.clear(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(1,fields.size()); - - // Add 5 new entries to cause evictions - for (int i=5;i<=9;i++) - entry[i]=ctx.add(field[i]); - fields.clear(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(0,fields.size()); - - } - - @Test - public void testRefSetClear() - { - // Only enough space for 5 entries - HpackContext ctx = new HpackContext(38*5); - - HttpField[] field = - { - new HttpField("fo0","b0r"), - new HttpField("fo1","b1r"), - new HttpField("fo2","b2r"), - new HttpField("fo3","b3r"), - new HttpField("fo4","b4r"), - new HttpField("fo5","b5r"), - new HttpField("fo6","b6r"), - new HttpField("fo7","b7r"), - new HttpField("fo8","b8r"), - new HttpField("fo9","b9r"), - new HttpField("foA","bAr"), - }; - Entry[] entry = new Entry[field.length]; - - // Add 5 entries - for (int i=0;i<=4;i++) - entry[i]=ctx.add(field[i]); - - // Add 3 entries to reference set - ctx.clearReferenceSet(); - ctx.addToRefSet(ctx.get(3)); - ctx.addToRefSet(ctx.get(1)); - ctx.addToRefSet(ctx.get(5)); - - // iterate ref set - HashSet<HttpField> fields = new HashSet<>(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(3,fields.size()); - assertTrue(fields.contains(field[0])); - assertTrue(fields.contains(field[2])); - assertTrue(fields.contains(field[4])); - - // Clear set - ctx.clearReferenceSet(); - fields.clear(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(0,fields.size()); - } @Test public void testResize() @@ -539,7 +335,7 @@ public class HpackContextTest assertEquals(5,ctx.size()); // check indexes - int index=5; + int index=66; for (int i=0;i<=4;i++) { assertEquals(index,ctx.index(entry[i])); @@ -547,89 +343,54 @@ public class HpackContextTest index--; } - // and statics have moved up 5 - assertEquals(":authority",ctx.get(1+5).getHttpField().getName()); - assertEquals(3+5,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3+5).getHttpField()); - assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName()); - assertEquals(null,ctx.get(62+5)); + // and statics have moved up 0 + assertEquals(":authority",ctx.get(1+0).getHttpField().getName()); + assertEquals(3+0,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+0).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName()); + assertEquals(null,ctx.get(62+ctx.size())); - // Add 3 entries to reference set - ctx.addToRefSet(ctx.get(3)); - ctx.addToRefSet(ctx.get(1)); - ctx.addToRefSet(ctx.get(5)); - - - - // iterate ref set - HashSet<HttpField> fields = new HashSet<>(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(3,fields.size()); - assertTrue(fields.contains(field[0])); - assertTrue(fields.contains(field[2])); - assertTrue(fields.contains(field[4])); // resize so that only 2 entries may be held ctx.resize(38*2); assertEquals(2,ctx.size()); // check indexes - index=2; + index=63; for (int i=3;i<=4;i++) { assertEquals(index,ctx.index(entry[i])); assertEquals(entry[i],ctx.get(index)); index--; } - - // and statics have moved up 2 - assertEquals(":authority",ctx.get(1+2).getHttpField().getName()); - assertEquals(3+2,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3+2).getHttpField()); - assertEquals("www-authenticate",ctx.get(61+2).getHttpField().getName()); - assertEquals(null,ctx.get(62+2)); - - // check reference set - fields.clear(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(1,fields.size()); - assertFalse(fields.contains(field[0])); - assertFalse(fields.contains(field[2])); - assertTrue(fields.contains(field[4])); - + // and statics have moved up 0 + assertEquals(":authority",ctx.get(1+0).getHttpField().getName()); + assertEquals(3+0,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+0).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName()); + assertEquals(null,ctx.get(62+ctx.size())); + // resize so that 6.5 entries may be held ctx.resize(38*6+19); assertEquals(2,ctx.size()); - // check indexes - index=2; + index=63; for (int i=3;i<=4;i++) { assertEquals(index,ctx.index(entry[i])); assertEquals(entry[i],ctx.get(index)); index--; } - - // and statics have moved up 2 - assertEquals(":authority",ctx.get(1+2).getHttpField().getName()); - assertEquals(3+2,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3+2).getHttpField()); - assertEquals("www-authenticate",ctx.get(61+2).getHttpField().getName()); - assertEquals(null,ctx.get(62+2)); - - // check reference set - fields.clear(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(1,fields.size()); - assertFalse(fields.contains(field[0])); - assertFalse(fields.contains(field[2])); - assertTrue(fields.contains(field[4])); + + // and statics have moved up 0 + assertEquals(":authority",ctx.get(1+0).getHttpField().getName()); + assertEquals(3+0,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+0).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName()); + assertEquals(null,ctx.get(62+ctx.size())); // Add 5 entries @@ -639,29 +400,21 @@ public class HpackContextTest assertEquals(6,ctx.size()); // check indexes - index=6; + index=67; for (int i=4;i<=9;i++) { assertEquals(index,ctx.index(entry[i])); assertEquals(entry[i],ctx.get(index)); index--; } + + // and statics have moved up 0 + assertEquals(":authority",ctx.get(1+0).getHttpField().getName()); + assertEquals(3+0,ctx.index(ctx.get(methodPost))); + assertEquals(methodPost,ctx.get(3+0).getHttpField()); + assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName()); + assertEquals(null,ctx.get(62+ctx.size())); - // and statics have moved up 6 - assertEquals(":authority",ctx.get(1+6).getHttpField().getName()); - assertEquals(3+6,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3+6).getHttpField()); - assertEquals("www-authenticate",ctx.get(61+6).getHttpField().getName()); - assertEquals(null,ctx.get(62+6)); - - // check reference set - fields.clear(); - for (Entry e: ctx.getReferenceSet() ) - fields.add(e.getHttpField()); - assertEquals(1,fields.size()); - assertFalse(fields.contains(field[0])); - assertFalse(fields.contains(field[2])); - assertTrue(fields.contains(field[4])); } @Test diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index 9fcb6ac5e9e..495fa90638e 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.util.TypeUtil; +import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -41,6 +42,7 @@ public class HpackDecoderTest { @Test + @Ignore public void testDecodeD_3() { HpackDecoder decoder = new HpackDecoder(4096,8192); @@ -91,6 +93,7 @@ public class HpackDecoderTest } @Test + @Ignore public void testDecodeD_4() { HpackDecoder decoder = new HpackDecoder(4096,8192); diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index 8286ab345c3..227dc434c86 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -79,34 +79,15 @@ public class HpackEncoderTest // All are in the header table Assert.assertEquals(4,encoder.getContext().size()); - - // All are in the reference set - HashSet<HttpField> refSet = new HashSet<>(); - for (Entry entry : encoder.getContext().getReferenceSet()) - refSet.add(entry.getHttpField()); - Assert.assertEquals(4,refSet.size()); - for (int i=0;i<=3;i++) - Assert.assertTrue(refSet.contains(field[i])); - + // encode exact same fields again! BufferUtil.clearToFill(buffer); encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); - // nothing should be encoded! - assertThat(buffer.remaining(),Matchers.is(0)); - // All are in the header table Assert.assertEquals(4,encoder.getContext().size()); - // All are in the reference set - refSet.clear(); - for (Entry entry : encoder.getContext().getReferenceSet()) - refSet.add(entry.getHttpField()); - Assert.assertEquals(4,refSet.size()); - for (int i=0;i<=3;i++) - Assert.assertTrue(refSet.contains(field[i])); - // Add 4 more fields for (int i=4;i<=7;i++) fields.add(field[i]); @@ -122,14 +103,6 @@ public class HpackEncoderTest // max header table size reached Assert.assertEquals(5,encoder.getContext().size()); - // last 5 in reference set - refSet.clear(); - for (Entry entry : encoder.getContext().getReferenceSet()) - refSet.add(entry.getHttpField()); - Assert.assertEquals(5,refSet.size()); - for (int i=3;i<=7;i++) - Assert.assertTrue(refSet.contains(field[i])); - // remove some fields for (int i=0;i<=7;i+=2) @@ -146,18 +119,6 @@ public class HpackEncoderTest // max header table size reached Assert.assertEquals(5,encoder.getContext().size()); - // last 5 in reference set - refSet.clear(); - for (Entry entry : encoder.getContext().getReferenceSet()) - refSet.add(entry.getHttpField()); - Assert.assertEquals(4,refSet.size()); - for (int i=0;i<=7;i++) - { - if (i%2==1) - Assert.assertTrue(refSet.contains(field[i])); - else - Assert.assertFalse(refSet.contains(field[i])); - } // remove another fields fields.remove(field[1].getName()); @@ -173,18 +134,6 @@ public class HpackEncoderTest // max header table size reached Assert.assertEquals(5,encoder.getContext().size()); - // last 5 in reference set - refSet.clear(); - for (Entry entry : encoder.getContext().getReferenceSet()) - refSet.add(entry.getHttpField()); - Assert.assertEquals(3,refSet.size()); - for (int i=2;i<=7;i++) - { - if (i%2==1) - Assert.assertTrue(refSet.contains(field[i])); - else - Assert.assertFalse(refSet.contains(field[i])); - } // re add the field @@ -201,40 +150,8 @@ public class HpackEncoderTest // max header table size reached Assert.assertEquals(5,encoder.getContext().size()); - // last 5 in reference set - refSet.clear(); - for (Entry entry : encoder.getContext().getReferenceSet()) - refSet.add(entry.getHttpField()); - Assert.assertEquals(4,refSet.size()); - for (int i=0;i<=7;i++) - { - if (i%2==1) - Assert.assertTrue(refSet.contains(field[i])); - else - Assert.assertFalse(refSet.contains(field[i])); - } } - @Test - public void testDoNotReferenceStatics() - { - HpackEncoder encoder = new HpackEncoder(38*5); - ByteBuffer buffer = BufferUtil.allocate(4096); - - HttpFields fields = new HttpFields(); - fields.put(":method","POST"); - - // encode - BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); - - // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); - - // empty header table - Assert.assertEquals(0,encoder.getContext().size()); - } @Test public void testNeverIndexSetCookie() diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java new file mode 100644 index 00000000000..e910ef98642 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java @@ -0,0 +1,133 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http2.hpack; + +import java.io.File; +import java.io.FileReader; +import java.io.FilenameFilter; +import java.nio.ByteBuffer; +import java.util.Map; + +import org.eclipse.jetty.http.FinalMetaData; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.ajax.JSON; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +public class HpackPerfTest +{ + int _maxHeaderTableSize=16*1024; + int _unencodedSize; + int _encodedSize; + + @Before + public void before() + { + _unencodedSize=0; + _encodedSize=0; + } + + @After + public void after() + { + System.err.printf("headertable=%d unencoded=%d encoded=%d%n",_maxHeaderTableSize,_unencodedSize,_encodedSize); + } + + @Test + public void simpleTest() throws Exception + { + runStories(_maxHeaderTableSize,new HpackEncoder(_maxHeaderTableSize,_maxHeaderTableSize)); + } + + private void runStories(int maxHeaderTableSize, HpackEncoder encoder) throws Exception + { + // Find files + File data = MavenTestingUtils.getTestResourceDir("data"); + String[] files = data.list(new FilenameFilter() + { + @Override + public boolean accept(File dir, String name) + { + return name.startsWith("story_"); + } + }); + + // Parse JSON + Map<String,Object>[] stories = new Map[files.length]; + int i=0; + for (String story : files) + stories[i++]=(Map<String,Object>)JSON.parse(new FileReader(new File(data,story))); + + ByteBuffer buffer = BufferUtil.allocate(256*1024); + + // Encode all the requests + encodeStories(buffer,stories,"request",encoder); + + // clear table + BufferUtil.clearToFill(buffer); + encoder.encodeMaxHeaderTableSize(buffer,0); + encoder.encodeMaxHeaderTableSize(buffer,maxHeaderTableSize); + BufferUtil.flipToFlush(buffer,0); + + // Encode all the responses + encodeStories(buffer,stories,"response",encoder); + + } + + private void encodeStories(ByteBuffer buffer,Map<String,Object>[] stories, String type, HpackEncoder encoder) throws Exception + { + for (Map<String,Object> story : stories) + { + if (type.equals(story.get("context"))) + { + // System.err.println(story); + Object[] cases = (Object[])story.get("cases"); + for (Object c : cases) + { + // System.err.println(" "+c); + Object[] headers = (Object[])((Map<String,Object>)c).get("headers"); + // System.err.println(" "+headers); + HttpFields fields = new HttpFields(); + for (Object header:headers) + { + Map<String,String> h = (Map<String,String>)header; + Map.Entry<String, String> e = h.entrySet().iterator().next(); + fields.add(e.getKey(),e.getValue()); + _unencodedSize+=e.getKey().length()+e.getValue().length(); + + } + + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + BufferUtil.flipToFlush(buffer,0); + _encodedSize+=buffer.remaining(); + + } + } + } + } + + +} diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_00.json b/jetty-http2/http2-hpack/src/test/resources/data/story_00.json new file mode 100644 index 00000000000..44d521f3fc0 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_00.json @@ -0,0 +1,53 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yahoo.co.jp" + }, + { + ":path": "/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.yahoo.co.jp" + }, + { + ":path": "/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/cmn/logo-ns-130528.png" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_01.json b/jetty-http2/http2-hpack/src/test/resources/data/story_01.json new file mode 100644 index 00000000000..54aab3bbcbc --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_01.json @@ -0,0 +1,52 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":scheme": "https" + }, + { + ":authority": "example.com" + }, + { + ":path": "/" + }, + { + ":method": "GET" + }, + { + "user-agent": "hpack-test" + }, + { + "cookie": "xxxxxxx1" + }, + { + "x-hello": "world" + } + ] + }, + { + "headers": [ + { + ":scheme": "https" + }, + { + ":authority": "example.com" + }, + { + ":path": "/" + }, + { + ":method": "GET" + }, + { + "user-agent": "hpack-test" + }, + { + "cookie": "xxxxxxx2" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_02.json b/jetty-http2/http2-hpack/src/test/resources/data/story_02.json new file mode 100644 index 00000000000..434857916ab --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_02.json @@ -0,0 +1,339 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "amazon.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "g-ecx.images-amazon.com" + }, + { + ":path": "/images/G/01/gno/beacon/BeaconSprite-US-01._V401903535_.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.amazon.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "g-ecx.images-amazon.com" + }, + { + ":path": "/images/G/01/x-locale/common/transparent-pixel._V386942464_.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.amazon.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "g-ecx.images-amazon.com" + }, + { + ":path": "/images/G/01/img12/other/disaster-relief/300-column/sandy-relief_300x75._V400689491_.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.amazon.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.amazon.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "g-ecx.images-amazon.com" + }, + { + ":path": "/images/G/01/x-locale/common/transparent-pixel._V192234675_.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.amazon.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "g-ecx.images-amazon.com" + }, + { + ":path": "/images/G/01/img12/shoes/sales_events/11_nov/1030_AccessoriesPROMO_GWright._V400626950_.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.amazon.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "g-ecx.images-amazon.com" + }, + { + ":path": "/images/G/01/Automotive/rotos/Duracell600_120._V192204764_.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.amazon.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "g-ecx.images-amazon.com" + }, + { + ":path": "/images/G/01/ui/loadIndicators/loadIndicator-large._V192195480_.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.amazon.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ecx.images-amazon.com" + }, + { + ":path": "/images/I/41HZ-ND-SUL._SL135_.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.amazon.com/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_03.json b/jetty-http2/http2-hpack/src/test/resources/data/story_03.json new file mode 100644 index 00000000000..3d7e5bed2a0 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_03.json @@ -0,0 +1,342 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "baidu.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "baidu.com" + }, + { + ":path": "/favicon.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.baidu.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.baidu.com" + }, + { + ":path": "/img/baidu_sylogo1.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + }, + { + "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.baidu.com" + }, + { + ":path": "/cache/global/img/gs.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + }, + { + "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s1.bdstatic.com" + }, + { + ":path": "/r/www/cache/global/js/tangram-1.3.4c1.0.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s1.bdstatic.com" + }, + { + ":path": "/r/www/cache/global/js/home-1.8.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s1.bdstatic.com" + }, + { + ":path": "/r/www/cache/user/js/u-1.3.4.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s1.bdstatic.com" + }, + { + ":path": "/r/www/img/i-1.0.0.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.baidu.com" + }, + { + ":path": "/favicon.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_04.json b/jetty-http2/http2-hpack/src/test/resources/data/story_04.json new file mode 100644 index 00000000000..3d7e5bed2a0 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_04.json @@ -0,0 +1,342 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "baidu.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "baidu.com" + }, + { + ":path": "/favicon.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.baidu.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.baidu.com" + }, + { + ":path": "/img/baidu_sylogo1.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + }, + { + "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.baidu.com" + }, + { + ":path": "/cache/global/img/gs.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + }, + { + "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s1.bdstatic.com" + }, + { + ":path": "/r/www/cache/global/js/tangram-1.3.4c1.0.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s1.bdstatic.com" + }, + { + ":path": "/r/www/cache/global/js/home-1.8.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s1.bdstatic.com" + }, + { + ":path": "/r/www/cache/user/js/u-1.3.4.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s1.bdstatic.com" + }, + { + ":path": "/r/www/img/i-1.0.0.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.baidu.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.baidu.com" + }, + { + ":path": "/favicon.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_05.json b/jetty-http2/http2-hpack/src/test/resources/data/story_05.json new file mode 100644 index 00000000000..dfcd8e1004a --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_05.json @@ -0,0 +1,366 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "geo.craigslist.org" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.craigslist.org" + }, + { + ":path": "/about/sites/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.craigslist.org" + }, + { + ":path": "/styles/countries.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.craigslist.org/about/sites/" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.craigslist.org" + }, + { + ":path": "/js/formats.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.craigslist.org/about/sites/" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.craigslist.org" + }, + { + ":path": "/js/jquery-1.4.2.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.craigslist.org/about/sites/" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.craigslist.org" + }, + { + ":path": "/favicon.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "shoals.craigslist.org" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.craigslist.org/about/sites/" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.craigslist.org" + }, + { + ":path": "/styles/craigslist.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://shoals.craigslist.org/" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.craigslist.org" + }, + { + ":path": "/js/formats.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://shoals.craigslist.org/" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.craigslist.org" + }, + { + ":path": "/js/homepage.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://shoals.craigslist.org/" + }, + { + "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_06.json b/jetty-http2/http2-hpack/src/test/resources/data/story_06.json new file mode 100644 index 00000000000..74dac51ef2e --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_06.json @@ -0,0 +1,342 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ebay.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.ebay.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ebay-stories.com" + }, + { + ":path": "/wp-content/uploads/2012/11/Iso-65.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.ebay.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "rover.ebay.com" + }, + { + ":path": "/roversync/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.ebay.com/" + }, + { + "cookie": "ebay=%5Esbf%3D%23%5E; dp1=bpbf/%238000000000005276504d^u1p/QEBfX0BAX19AQA**5276504d^; cssg=c67883f113a0a56964e646c6ffaa1abe; s=CgAD4ACBQlm5NYzY3ODgzZjExM2EwYTU2OTY0ZTY0NmM2ZmZhYTFhYmUBSgAYUJZuTTUwOTUxY2NkLjAuMS4zLjE1MS4zLjAuMeN+7JE*; nonsession=CgAFMABhSdlBNNTA5NTFjY2QuMC4xLjEuMTQ5LjMuMC4xAMoAIFn7Hk1jNjc4ODNmMTEzYTBhNTY5NjRlNjQ2YzZmZmFhMWFjMQDLAAFQlSPVMX8u5Z8*" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "p.ebaystatic.com" + }, + { + ":path": "/aw/pics/s.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.ebay.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "p.ebaystatic.com" + }, + { + ":path": "/aw/pics/mops/2012_doodles/Holiday/DS3/ImgWeek_1_Penguin_Small_150x30.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.ebay.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "p.ebaystatic.com" + }, + { + ":path": "/aw/pics/globalHeader/facebook/g12.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.ebay.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "p.ebaystatic.com" + }, + { + ":path": "/aw/pics/globalHeader/twitter/g12.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.ebay.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "p.ebaystatic.com" + }, + { + ":path": "/aw/pics/globalHeader/icon_mobile_gray_11x16.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.ebay.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "srx.main.ebayrtm.com" + }, + { + ":path": "/rtm" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.ebay.com/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_07.json b/jetty-http2/http2-hpack/src/test/resources/data/story_07.json new file mode 100644 index 00000000000..cabe2c30a51 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_07.json @@ -0,0 +1,345 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yb/r/GsNJNwuI-UM.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.facebook.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yY/r/u8iA3kXb8Y1.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.facebook.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yI/r/qANVTsC52fp.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.facebook.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yt/r/FZaMKqARgC6.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.facebook.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yZ/r/jlKDoX15kHG.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.facebook.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yO/r/_MRarphcCIq.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.facebook.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yP/r/CRkiDDWTd1u.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.facebook.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yX/x/Qq6L1haQrYr.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://static.ak.fbcdn.net/rsrc.php/v2/yI/r/qANVTsC52fp.css" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/yN/r/EarbWo_mDU-.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.facebook.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "static.ak.fbcdn.net" + }, + { + ":path": "/rsrc.php/v2/y7/x/9jt7oVdF7z3.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://static.ak.fbcdn.net/rsrc.php/v2/yO/r/_MRarphcCIq.css" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_08.json b/jetty-http2/http2-hpack/src/test/resources/data/story_08.json new file mode 100644 index 00000000000..f0fefde517f --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_08.json @@ -0,0 +1,363 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "flickr.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.flickr.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "us.adserver.yahoo.com" + }, + { + ":path": "/a" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.flickr.com/" + }, + { + "cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.flickr.com" + }, + { + ":path": "/images/share-this-icons-sprite.png.v6" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus" + }, + { + "referer": "http://www.flickr.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.flickr.com" + }, + { + ":path": "/images/flickr-sprite.png.v4" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.flickr.com/" + }, + { + "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.flickr.com" + }, + { + ":path": "/flanal_event.gne" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus; ywadp10001561398679=1956875541" + }, + { + "referer": "http://www.flickr.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "y.analytics.yahoo.com" + }, + { + ":path": "/fpc.pl" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.flickr.com/" + }, + { + "cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "d.yimg.com" + }, + { + ":path": "/ce/soup/soup_generated_fragment.gne" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.flickr.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "geo.yahoo.com" + }, + { + ":path": "/b" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.flickr.com/" + }, + { + "cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.flickr.com" + }, + { + ":path": "/photos/nasacommons/4940913342/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus; ywadp10001561398679=1956875541; fl_v=souhp; fpc10001561398679=Qvv1ikW_|aUqazlyMaa|fses10001561398679=|aUqazlyMaa|Qvv1ikW_|fvis10001561398679=Zj1odHRwJTNBJTJGJTJGd3d3LmZsaWNrci5jb20lMkYmdD0xMzUxOTUwMDc1JmI9JTJGaW5kZXhfc291cC5nbmU=|8M1871YYH0|8M1871YYH0|8M1871YYH0|8|8M1871YYH0|8M1871YYH0" + }, + { + "referer": "http://www.flickr.com/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_09.json b/jetty-http2/http2-hpack/src/test/resources/data/story_09.json new file mode 100644 index 00000000000..b922bc78106 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_09.json @@ -0,0 +1,345 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "linkedin.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.linkedin.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s.c.lnkd.licdn.com" + }, + { + ":path": "/scds/concat/common/js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.linkedin.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s.c.lnkd.licdn.com" + }, + { + ":path": "/scds/concat/common/css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.linkedin.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s.c.lnkd.licdn.com" + }, + { + ":path": "/scds/concat/common/js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.linkedin.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s.c.lnkd.licdn.com" + }, + { + ":path": "/scds/concat/common/css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.linkedin.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s.c.lnkd.licdn.com" + }, + { + ":path": "/scds/concat/common/css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.linkedin.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s.c.lnkd.licdn.com" + }, + { + ":path": "/scds/concat/common/js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.linkedin.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.linkedin.com" + }, + { + ":path": "/analytics/noauthtracker" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "x-requested-with": "XMLHttpRequest" + }, + { + "referer": "http://www.linkedin.com/" + }, + { + "cookie": "bcookie=\"v=2&bae845a5-83ed-4590-becf-f0f3d586432b\"; leo_auth_token=\"GST:UDbWFFpLLdcS6gHJ7NJa3XYRsc7W_gDwutbWnlWLfo7G_2Y4jfLH-H:1351948419:4b5c0f1309310a9b659b97d8960e64fdd635526b\"; JSESSIONID=\"ajax:0608630266152992729\"; visit=\"v=1&G\"; X-LI-IDC=C1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "s.c.lnkd.licdn.com" + }, + { + ":path": "/scds/common/u/img/favicon_v3.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.linkedin.com/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_10.json b/jetty-http2/http2-hpack/src/test/resources/data/story_10.json new file mode 100644 index 00000000000..686aa684bd4 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_10.json @@ -0,0 +1,339 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "msn.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.msn.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ads1.msads.net" + }, + { + ":path": "/library/primedns.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.msn.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "col.stj.s-msn.com" + }, + { + ":path": "/primedns.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.msn.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "blu.stc.s-msn.com" + }, + { + ":path": "/as/wea3/i/en-us/law/39.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.msn.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "col.stj.s-msn.com" + }, + { + ":path": "/primedns.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.msn.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "col.stc.s-msn.com" + }, + { + ":path": "/br/sc/i/ff/adchoices_gif2.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.msn.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "col.stb00.s-msn.com" + }, + { + ":path": "/i/80/53CAC6A10B6248682CF221B24A92.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.msn.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "col.stb01.s-msn.com" + }, + { + ":path": "/i/E0/A6C312635EF0A355668C820EB5343.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.msn.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "col.stb00.s-msn.com" + }, + { + ":path": "/i/BB/B1F619A1AD4D4AA6B0648BDBBCDEED.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.msn.com/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_11.json b/jetty-http2/http2-hpack/src/test/resources/data/story_11.json new file mode 100644 index 00000000000..cc86a093107 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_11.json @@ -0,0 +1,369 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "nytimes.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "t.pointroll.com" + }, + { + ":path": "/PointRoll/Track/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.bbc.co.uk/news/business-20178000" + }, + { + "cookie": "PRbu=EzZdduhgq; PRgo=BBBAAFMnA; PRti4CD975E46CAEA=B" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "t.pointroll.com" + }, + { + ":path": "/PointRoll/Track/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.bbc.co.uk/news/business-20178000" + }, + { + "cookie": "PRbu=EzZdduhgq; PRgo=BBBAAFMnA; PRti4CD975E46CAEA=B" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "graphics8.nytimes.com" + }, + { + ":path": "/packages/css/multimedia/bundles/projects/2012/HPLiveDebateFlex.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.nytimes.com/" + }, + { + "cookie": "RMID=007f010022166047bee9002b; adxcs=-" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "graphics8.nytimes.com" + }, + { + ":path": "/js/app/common/slideshow/embeddedSlideshowBuilder.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.nytimes.com/" + }, + { + "cookie": "RMID=007f010022166047bee9002b; adxcs=-" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "graphics8.nytimes.com" + }, + { + ":path": "/css/0.1/screen/slideshow/modules/slidingGallery.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.nytimes.com/" + }, + { + "cookie": "RMID=007f010022166047bee9002b; adxcs=-" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "graphics8.nytimes.com" + }, + { + ":path": "/adx/images/ADS/31/46/ad.314668/NYT_MBM_IPHON_LEFT_Oct11.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.nytimes.com/" + }, + { + "cookie": "RMID=007f010022166047bee9002b; adxcs=-" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "graphics8.nytimes.com" + }, + { + ":path": "/packages/js/multimedia/bundles/projects/2012/HPLiveDebateFlex.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.nytimes.com/" + }, + { + "cookie": "RMID=007f010022166047bee9002b; adxcs=-" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "graphics8.nytimes.com" + }, + { + ":path": "/packages/js/multimedia/data/FilmStripPromo/2012_election_filmstrip.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.nytimes.com/" + }, + { + "cookie": "RMID=007f010022166047bee9002b; adxcs=-" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "graphics8.nytimes.com" + }, + { + ":path": "/packages/js/elections/2012/debates/videostrip/filmstrip.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.nytimes.com/" + }, + { + "cookie": "RMID=007f010022166047bee9002b; adxcs=-" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_12.json b/jetty-http2/http2-hpack/src/test/resources/data/story_12.json new file mode 100644 index 00000000000..3b27fd7f96d --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_12.json @@ -0,0 +1,369 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "pinterest.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/164311086374323731_DhZSfIfc_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/161637074097583855_SNjDRMKe_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/273593746083022624_FCoEkXsC_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/52917364342893663_qtPmJgkx_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/116952921544035902_KyTWinzm_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/283445370267774252_AttBMVfT_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/237142736599025827_ufDEHdRe_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/224194887669533381_UBmi659g_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "media-cache-lt0.pinterest.com" + }, + { + ":path": "/upload/274156696036479907_A1ezgnsj_b.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://pinterest.com/" + }, + { + "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\"" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_13.json b/jetty-http2/http2-hpack/src/test/resources/data/story_13.json new file mode 100644 index 00000000000..a692cb52650 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_13.json @@ -0,0 +1,342 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "qq.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mat1.gtimg.com" + }, + { + ":path": "/www/images/qq2012/followme.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mat1.gtimg.com" + }, + { + ":path": "/www/images/qq2012/sosologo.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mat1.gtimg.com" + }, + { + ":path": "/www/images/qq2012/festival/da18search.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mat1.gtimg.com" + }, + { + ":path": "/www/images/qq2012/festival/da18bodybg05.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mat1.gtimg.com" + }, + { + ":path": "/www/images/qq2012/loginall_1.2.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mat1.gtimg.com" + }, + { + ":path": "/www/images/qq2012/aikanLoading1.1.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mat1.gtimg.com" + }, + { + ":path": "/joke/Koala/Qfast1.0.1.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mat1.gtimg.com" + }, + { + ":path": "/www/images/qq2012/mobileNews.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "img1.gtimg.com" + }, + { + ":path": "/v/pics/hv1/241/117/1186/77149726.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.qq.com/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_14.json b/jetty-http2/http2-hpack/src/test/resources/data/story_14.json new file mode 100644 index 00000000000..c07d85f9d5f --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_14.json @@ -0,0 +1,339 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "sina.com.cn" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.sina.com.cn" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "news.sina.com.cn" + }, + { + ":path": "/js/87/20121024/201218ConfTop.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.sina.com.cn/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "int.dpool.sina.com.cn" + }, + { + ":path": "/iplookup/iplookup.php" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.sina.com.cn/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i3.sinaimg.cn" + }, + { + ":path": "/video/2012/1103/U7805P167DT20121103211853.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.sina.com.cn/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i3.sinaimg.cn" + }, + { + ":path": "/home/2012/1102/U6041P30DT20121102122146.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.sina.com.cn/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i3.sinaimg.cn" + }, + { + ":path": "/home/deco/2009/0330/logo_home.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.sina.com.cn/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "d1.sina.com.cn" + }, + { + ":path": "/shh/lechan/20121016sina/logo1.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.sina.com.cn/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i0.sinaimg.cn" + }, + { + ":path": "/home/2012/1103/U8551P30DT20121103063734.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.sina.com.cn/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i1.sinaimg.cn" + }, + { + ":path": "/home/2012/1101/U6648P30DT20121101141432.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.sina.com.cn/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_15.json b/jetty-http2/http2-hpack/src/test/resources/data/story_15.json new file mode 100644 index 00000000000..1bd29a32859 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_15.json @@ -0,0 +1,336 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "taobao.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.taobao.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.taobao.com" + }, + { + ":path": "/index_global.php" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "a.tbcdn.cn" + }, + { + ":path": "/p/fp/2011a/assets/space.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.taobao.com/index_global.php" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "a.tbcdn.cn" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.taobao.com/index_global.php" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "a.tbcdn.cn" + }, + { + ":path": "/p/fp/2011hk/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.taobao.com/index_global.php" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "a.tbcdn.cn" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.taobao.com/index_global.php" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "a.tbcdn.cn" + }, + { + ":path": "/p/fp/2010c/js/fp-direct-promo-min.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.taobao.com/index_global.php" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "img01.taobaocdn.com" + }, + { + ":path": "/tps/i1/T1fqY2XilfXXahsVgc-1000-40.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.taobao.com/index_global.php" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "img01.taobaocdn.com" + }, + { + ":path": "/tps/i1/T1rZiwXgtfXXXXXXXX-110-135.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.taobao.com/index_global.php" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_16.json b/jetty-http2/http2-hpack/src/test/resources/data/story_16.json new file mode 100644 index 00000000000..e638e7d21f9 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_16.json @@ -0,0 +1,375 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "en.wikipedia.org" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "centralnotice_bucket=1; clicktracking-session=eJko6IiUcEm69ehQfaakQlJfiLy9lShNP; mediaWiki.user.bucket%3Aext.articleFeedback-tracking=10%3Atrack; mediaWiki.user.id=EM83jsjaqPzIMLwBTiKF3aLiiTKeweez; mediaWiki.user.bucket%3Aext.articleFeedback-options=8%3Ashow" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "en.wikipedia.org" + }, + { + ":path": "/wiki/Main_Page" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "centralnotice_bucket=1; clicktracking-session=eJko6IiUcEm69ehQfaakQlJfiLy9lShNP; mediaWiki.user.bucket%3Aext.articleFeedback-tracking=10%3Atrack; mediaWiki.user.id=EM83jsjaqPzIMLwBTiKF3aLiiTKeweez; mediaWiki.user.bucket%3Aext.articleFeedback-options=8%3Ashow" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "bits.wikimedia.org" + }, + { + ":path": "/en.wikipedia.org/load.php" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://en.wikipedia.org/wiki/Main_Page" + }, + { + "if-modified-since": "Wed, 31 Oct 2012 17:52:04 GMT" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "bits.wikimedia.org" + }, + { + ":path": "/en.wikipedia.org/load.php" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://en.wikipedia.org/wiki/Main_Page" + }, + { + "if-modified-since": "Thu, 01 Nov 2012 09:33:27 GMT" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "bits.wikimedia.org" + }, + { + ":path": "/en.wikipedia.org/load.php" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://en.wikipedia.org/wiki/Main_Page" + }, + { + "if-modified-since": "Sat, 03 Nov 2012 12:53:27 GMT" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "bits.wikimedia.org" + }, + { + ":path": "/en.wikipedia.org/load.php" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://en.wikipedia.org/wiki/Main_Page" + }, + { + "if-modified-since": "Wed, 31 Oct 2012 17:52:04 GMT" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "bits.wikimedia.org" + }, + { + ":path": "/en.wikipedia.org/load.php" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://en.wikipedia.org/wiki/Main_Page" + }, + { + "if-modified-since": "Thu, 01 Nov 2012 09:33:27 GMT" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "upload.wikimedia.org" + }, + { + ":path": "/wikipedia/en/c/ca/Kanthirava_cropped.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://en.wikipedia.org/wiki/Main_Page" + }, + { + "if-modified-since": "Fri, 02 Nov 2012 23:46:59 GMT" + }, + { + "if-none-match": "288bdb2fd5e5a4f7272f58fcb083a7e1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "upload.wikimedia.org" + }, + { + ":path": "/wikipedia/commons/thumb/d/d2/Dancing_girl_ajanta_%28cropped%29.jpg/72px-Dancing_girl_ajanta_%28cropped%29.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://en.wikipedia.org/wiki/Main_Page" + }, + { + "if-modified-since": "Tue, 30 Oct 2012 17:37:15 GMT" + }, + { + "if-none-match": "6e8d56df9be35494b4d9f0ea72ed1a3e" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "bits.wikimedia.org" + }, + { + ":path": "/en.wikipedia.org/load.php" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://en.wikipedia.org/wiki/Main_Page" + }, + { + "if-modified-since": "Sat, 03 Nov 2012 12:53:27 GMT" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_17.json b/jetty-http2/http2-hpack/src/test/resources/data/story_17.json new file mode 100644 index 00000000000..50fa4ca87fc --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_17.json @@ -0,0 +1,348 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yahoo.co.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.yahoo.co.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/clr/1/clr-121025.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp/logo.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_1.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/weather/general/transparent_s/clouds.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/weather/general/transparent_s/sun.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_2.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/premium/contents/bnr/2012/50x50/0928_store_supernatural.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_18.json b/jetty-http2/http2-hpack/src/test/resources/data/story_18.json new file mode 100644 index 00000000000..43377fba2d3 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_18.json @@ -0,0 +1,351 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yahoo.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "d.yimg.com" + }, + { + ":path": "/hd/ch7news/7_world/1103_0700_nat_elephant_sml_1898chj-1898chl.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://au.yahoo.com/?p=us" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "au.yahoo.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "B=4m2rqu589a507&b=3&s=1v" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "d.yimg.com" + }, + { + ":path": "/mi/ywa.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://au.yahoo.com/?p=us" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yui.yahooapis.com" + }, + { + ":path": "/combo" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://au.yahoo.com/?p=us" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "secure-au.imrworldwide.com" + }, + { + ":path": "/cgi-bin/m" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://au.yahoo.com/?p=us" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "chart.finance.yahoo.com" + }, + { + ":path": "/instrument/1.0/%5Eaxjo/chart;range=5d/image;size=179x98" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://au.yahoo.com/?p=us" + }, + { + "cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "chart.finance.yahoo.com" + }, + { + ":path": "/instrument/1.0/%5Eaord/chart;range=5d/image;size=179x98" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://au.yahoo.com/?p=us" + }, + { + "cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "chart.finance.yahoo.com" + }, + { + ":path": "/instrument/1.0/audusd=x/chart;range=5d/image;size=179x98" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://au.yahoo.com/?p=us" + }, + { + "cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "cm.au.yahoo.overture.com" + }, + { + ":path": "/js_flat_1_0/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://au.yahoo.com/?p=us" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_19.json b/jetty-http2/http2-hpack/src/test/resources/data/story_19.json new file mode 100644 index 00000000000..fe8dd3a237b --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_19.json @@ -0,0 +1,345 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yandex.ru" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.yandex.ru" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yabs.yandex.ru" + }, + { + ":path": "/count/Vnw_3zF2dkO40002Zhl8KGa5KPK2cmPfMeYpO2zG0vAeOuAefZIAgoA2KAe2fPOOP96yq4ba1fDKGQC1hlDVeQN8GfVD17e7" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yandex.ru/" + }, + { + "cookie": "t=p; yandexuid=6410453771351949451" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yabs.yandex.ru" + }, + { + ":path": "/count/Vnw_3mft8wq40000Zhl8KGa5KP6yq4ba1fDKhlDVeQN8GfVD17a3=qcOn49K2cmPfMcbQagXZWgYAgoA2KAMM66IcD7W3" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yandex.ru/" + }, + { + "cookie": "t=p; yandexuid=6410453771351949451" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yandex.st" + }, + { + ":path": "/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yandex.st" + }, + { + ":path": "/www/1.359/www/i/yandex3.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yandex.ru/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yandex.st" + }, + { + ":path": "/morda-logo/i/logo.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yandex.ru/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "mc.yandex.ru" + }, + { + ":path": "/watch/722545" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yandex.ru/" + }, + { + "cookie": "t=p; yandexuid=6410453771351949451" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yandex.st" + }, + { + ":path": "/www/1.359/www/pages-desktop/www-css/_www-css.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yandex.ru/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yandex.st" + }, + { + ":path": "/www/_/_r7pp-b-hKoDbgyGYy0IB3wlkno.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yandex.ru/" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_20.json b/jetty-http2/http2-hpack/src/test/resources/data/story_20.json new file mode 100644 index 00000000000..f86f11a052c --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_20.json @@ -0,0 +1,5674 @@ +{ + "context": "request", + "cases": [ + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yahoo.co.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.yahoo.co.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/clr/1/clr-121025.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp/logo.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_1.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/weather/general/transparent_s/clouds.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/weather/general/transparent_s/sun.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_2.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/premium/contents/bnr/2012/50x50/0928_store_supernatural.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_3.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_5.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/500052/1080894/20121029/meulz5rknmobtjfqmyz8-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/70506/1082209/20121024/ffmwiwdybofwysftxna1-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/yahoo/javascript/yfa_visual5_tbp.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.yahoo.co.jp" + }, + { + ":path": "/javascript/fp_base_bd_ga_5.0.42.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/yahoo/javascript/csc/20060824/lib2obf_b6.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/pr/tb_bg-120110.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/uhd/homepage_bg-120123.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/sicons/bookstore16.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/sicons/movie16.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/sicons/game16.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/cmn/pic_all-121004.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/sicons/fortune16.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/emg/disaster_ttl2.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/video-topics/rec/1211/03_e01.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/clr/1/clr-121025.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://k.yimg.jp/images/top/sp2/clr/1/clr-121025.css" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/cmp/comp_all-121012.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "k.yimg.jp" + }, + { + ":path": "/images/top/sp2/spotlight/2011/1031o.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "news.c.yimg.jp" + }, + { + ":path": "/images/topics/20121103-00000193-sph-000-thumb.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/2237/1080330/20121103/bg6so7sbgcqenc9py6xk-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "www.yahoo.co.jp" + }, + { + ":path": "/favicon.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/images/security/pf/yjsecure.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/js/yjaxc.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "dailynews.yahoo.co.jp" + }, + { + ":path": "/fc/sports/nippon_series/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://www.yahoo.co.jp/" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJTOPICSFBREAD=d=juTus3MJdA6fAPKQn3MJyoWvkTaY6I2RngPiVKE3BMv8AFX.C4TMg0utwM_uXg_sKn7y2yDVFKE-&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "dailynews.yahoo.co.jp" + }, + { + ":path": "/fc/js/fb_pc.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJTOPICSFBREAD=d=juTus3MJdA6fAPKQn3MJyoWvkTaY6I2RngPiVKE3BMv8AFX.C4TMg0utwM_uXg_sKn7y2yDVFKE-&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/71629/1073618/20121029/ypxcyyekc_ruhypdisqu-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/fc.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/icon/photo.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/mh/news.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/30/1077242/20121029/ixbislu9ygczxzdkfnpt-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/facebook/news_Facebook_76x76.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/rapid/1.5.0/ult.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/new2.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/nestopics_icon_40.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/yahoo/javascript/yfa_visual5.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/193/1072227/20121029/uyzwkpexjszyi2zgct4p-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/2959/1085127/20121102/dalvv9p9fw9tribawawe-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/2959/1085124/20121102/bz9rzgnremydaxbp4ihb-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/editor/topics_pr_linkimg_l2.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "lpt.c.yimg.jp" + }, + { + ":path": "/im_sigg537mI30DS9hWeZeGpWl75Q---x200-y190-q90/amd/20121103-00000542-sanspo-000-view.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "amd.c.yimg.jp" + }, + { + ":path": "/im_siggHulEjLwgzPyrVDkZ9oNPng---x200-y133-q90/amd/20121031-00005828-yj_corptrend-000-51670401-view.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "amd.c.yimg.jp" + }, + { + ":path": "/im_siggrMDL3ZpnqnwM4Z1FYvhX2Q---x200-y133-q90/amd/20121101-00005830-yj_corptrend-000-51751400-view.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/css/import_ver2.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/commerce/js/libs/jquery/core/1.4.2/jquery.min.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/yui/jp/uhd/olympic/1.0.2/img/uhdChnk.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/yn_gnavi_sprite_20120926.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/social/btnMx.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/ytopics_sprite_icons.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/ytopics_sprite_backgrounds.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/relTabLeft.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/relTabRight.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/bullet_list.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/yui/jp/uft/1.0.0/img/utfChnk.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/accountTitleBg.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/social/sprite_icoSns16.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/topics/wiki/trendTitleBg.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/yahoo/javascript/csc/20060824/lib2obf_b4.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ah.yimg.jp" + }, + { + ":path": "/bdv/164354/1084075/20121101/4feasfvz47csxcoydlvl-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "platform.twitter.com" + }, + { + ":path": "/widgets.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "platform.twitter.com" + }, + { + ":path": "/widgets/tweet_button.1351848862.html" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "connect.facebook.net" + }, + { + ":path": "/ja_JP/all.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "bkskapi.dailynews.yahoo.co.jp" + }, + { + ":path": "/detail" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJTOPICSFBREAD=d=juTus3MJdA6fAPKQn3MJyoWvkTaY6I2RngPiVKE3BMv8AFX.C4TMg0utwM_uXg_sKn7y2yDVFKE-&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "platform.twitter.com" + }, + { + ":path": "/widgets/follow_button.1351848862.html" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "p.twitter.com" + }, + { + ":path": "/t.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://platform.twitter.com/widgets/tweet_button.1351848862.html" + }, + { + "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "cdn.api.twitter.com" + }, + { + ":path": "/1/urls/count.json" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://platform.twitter.com/widgets/tweet_button.1351848862.html" + }, + { + "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "r.twimg.com" + }, + { + ":path": "/jot" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://platform.twitter.com/widgets/tweet_button.1351848862.html" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "cdn.api.twitter.com" + }, + { + ":path": "/1/users/show.json" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://platform.twitter.com/widgets/follow_button.1351848862.html" + }, + { + "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "p.twitter.com" + }, + { + ":path": "/f.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://platform.twitter.com/widgets/follow_button.1351848862.html" + }, + { + "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "r.twimg.com" + }, + { + ":path": "/jot" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://platform.twitter.com/widgets/follow_button.1351848862.html" + } + ] + }, + { + "headers": [ + { + ":method": "POST" + }, + { + ":scheme": "http" + }, + { + ":authority": "ocsp.verisign.com" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "115" + }, + { + "content-type": "application/ocsp-request" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "dailynews.yahoo.co.jp" + }, + { + ":path": "/favicon.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJTOPICSFBREAD=d=juTus3MJdA6fAPKQn3MJyoWvkTaY6I2RngPiVKE3BMv8AFX.C4TMg0utwM_uXg_sKn7y2yDVFKE-&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/css/yj2.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/clear.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/cobranding/sanspo.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/json/jsr_class_1_1.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "headlines.yahoo.co.jp" + }, + { + ":path": "/hl" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/socialModule/realtimeSearch_1_0-min.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/jquery/jquery.template.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/socialModule/facebook_1_3_1-min.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "amd.c.yimg.jp" + }, + { + ":path": "/im_siggvNnG417_XZJF5TsJPh7FFQ---x200-y190-q90/amd/20121103-00000542-sanspo-000-4-view.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/70506/1082210/20121024/0ffcv4drh8ir07jvroju-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/71629/1082189/20121029/2n1tdzicd8j7eotfexbi-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/jquery/jquery.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/widgets/widgets_1_1.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/2959/1085127/20121102/ilaj2_d_zo_9bjginqty-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/2959/1085124/20121102/vval_chos32k_7okick9-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/30/1072134/20121029/qv2c_lhjbra0qr5ps55w-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/css/master-news.css" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/css,*/*;q=0.1" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/news_socialbutton.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/media/ymui/img/lineWide_4x1.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/yn_sprite_icons.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/media/ymui/img/carrrot_2.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/media/ymui/img/photoNew_45x15.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/sprite_bgRTSearchBox.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/sprite_icoTwitter.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/yn_sprite_background.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/ranking.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/v1/yn_gnavi_sprite.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/yui/jp/ult/arrow.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/listing/tool/yjaxc/yjaxc-iframe.html" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "realtime.search.yahooapis.jp" + }, + { + ":path": "/v1/post" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/widgets/tweet_button.html" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/listing/tool/yjaxc/yjaxc-iframe.html?src0=http%3A%2F%2Fyjaxc.yahoo.co.jp%2Foi%3Fs%3Danemos_news01295%26i%3D2078709534%26w%3D%26apg%3D1%26t%3Dj%26u%3Dhttp%253A%252F%252Fheadlines.yahoo.co.jp%252Fhl%253Fa%253D20121103-00000542-sanspo-base%26ref%3Dhttp%253A%252F%252Fdailynews.yahoo.co.jp%252Ffc%252Fsports%252Fnippon_series%252F%253F1351933494%26enc%3DEUC-JP%26spaceId%3D%26jisx0402%3D%26type%3D%26crawlUrl%3D&src1=http%3A%2F%2Fyjaxc.yahoo.co.jp%2Fjs%2Fyjaxc-internal-banner.js%3Fimgurl%3Dhttp%253A%252F%252Fah.yimg.jp%252Fimages%252Fim%252Finnerad%252F%26imgpath%3Dbnr1_ss_1_300-250.jpg%26clickurl%3Dhttp%253A%252F%252Frd.yahoo.co.jp%252Fbzc%252Fsds%252F97648%252Fevt%253D97648%252F*http%253A%252F%252Flisting.yahoo.co.jp%252Fy_promo%252Flisting01%252F%253Fo%253DJP1350" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "headlines.yahoo.co.jp" + }, + { + ":path": "/sc/show" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ah.yimg.jp" + }, + { + ":path": "/bdv/164354/1080825/20121101/hii0znrxvsbx0dt01k_g-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/widgets/images/tweet.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/lib/news/widgets/tweet_button.html?_=1351949189638&count=none&id=twitter_tweet_button_2&lang=ja&original_referer=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base&redirect=&text=%E5%B7%A8%E4%BA%BA%E3%81%8C%EF%BC%93%E5%B9%B4%E3%81%B6%E3%82%8A%E6%97%A5%E6%9C%AC%E4%B8%80%EF%BC%81%E5%BE%A9%E5%B8%B0%E3%81%AE%E9%98%BF%E9%83%A8%E3%81%8C%E6%B1%BA%E5%8B%9D%E6%89%93%EF%BC%88%E3%82%B5%E3%83%B3%E3%82%B1%E3%82%A4%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%84%EF%BC%89%20-%20Y!%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&url=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/widgets/images/tweet_ja.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/lib/news/widgets/tweet_button.html?_=1351949189638&count=none&id=twitter_tweet_button_2&lang=ja&original_referer=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base&redirect=&text=%E5%B7%A8%E4%BA%BA%E3%81%8C%EF%BC%93%E5%B9%B4%E3%81%B6%E3%82%8A%E6%97%A5%E6%9C%AC%E4%B8%80%EF%BC%81%E5%BE%A9%E5%B8%B0%E3%81%AE%E9%98%BF%E9%83%A8%E3%81%8C%E6%B1%BA%E5%8B%9D%E6%89%93%EF%BC%88%E3%82%B5%E3%83%B3%E3%82%B1%E3%82%A4%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%84%EF%BC%89%20-%20Y!%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&url=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/lib/news/widgets/tweet_button.html" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "puffer.c.yimg.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "puffer.c.yimg.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "puffer.c.yimg.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "puffer.c.yimg.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/images/im/imgim/pc2/im1001149230pcmr1.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/listing/tool/yjaxc/yjaxc-iframe.html?src0=http%3A%2F%2Fyjaxc.yahoo.co.jp%2Foi%3Fs%3Danemos_news01295%26i%3D2078709534%26w%3D%26apg%3D1%26t%3Dj%26u%3Dhttp%253A%252F%252Fheadlines.yahoo.co.jp%252Fhl%253Fa%253D20121103-00000542-sanspo-base%26ref%3Dhttp%253A%252F%252Fdailynews.yahoo.co.jp%252Ffc%252Fsports%252Fnippon_series%252F%253F1351933494%26enc%3DEUC-JP%26spaceId%3D%26jisx0402%3D%26type%3D%26crawlUrl%3D&src1=http%3A%2F%2Fyjaxc.yahoo.co.jp%2Fjs%2Fyjaxc-internal-banner.js%3Fimgurl%3Dhttp%253A%252F%252Fah.yimg.jp%252Fimages%252Fim%252Finnerad%252F%26imgpath%3Dbnr1_ss_1_300-250.jpg%26clickurl%3Dhttp%253A%252F%252Frd.yahoo.co.jp%252Fbzc%252Fsds%252F97648%252Fevt%253D97648%252F*http%253A%252F%252Flisting.yahoo.co.jp%252Fy_promo%252Flisting01%252F%253Fo%253DJP1350" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "urls.api.twitter.com" + }, + { + ":path": "/1/urls/count.json" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/lib/news/widgets/tweet_button.html?_=1351949189638&count=none&id=twitter_tweet_button_2&lang=ja&original_referer=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base&redirect=&text=%E5%B7%A8%E4%BA%BA%E3%81%8C%EF%BC%93%E5%B9%B4%E3%81%B6%E3%82%8A%E6%97%A5%E6%9C%AC%E4%B8%80%EF%BC%81%E5%BE%A9%E5%B8%B0%E3%81%AE%E9%98%BF%E9%83%A8%E3%81%8C%E6%B1%BA%E5%8B%9D%E6%89%93%EF%BC%88%E3%82%B5%E3%83%B3%E3%82%B1%E3%82%A4%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%84%EF%BC%89%20-%20Y!%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&url=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base" + }, + { + "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "puffer.c.yimg.jp" + }, + { + ":path": "/" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "headlines.yahoo.co.jp" + }, + { + ":path": "/favicon.ico" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "headlines.yahoo.co.jp" + }, + { + ":path": "/hl" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/images/tech/bcn1.js" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/3124/1073472/20121029/mkgcwzthl_hbpnxy_tno-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/71629/1074517/20121029/kqo8rgbu_aykmxxf3cqf-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/media/ymui/img/carrrot_5.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/2959/1085127/20121102/crs1gvpzl74_ilnbd8yl-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/bylines/v201209/main/bnr/bnr_300x90.png" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/twitter/tw_spo_300_60.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/193/1074340/20121029/rhnusvihwpg9khhap9vn-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/1862/1083691/20121030/fk8wxszqyglpfwkac5kl-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "headlines.yahoo.co.jp" + }, + { + ":path": "/hl" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/71629/1082190/20121029/_xhxh5ukdv3s6oigo4bq-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/71629/1075880/20121029/vstketkrv3fci_zfj0fb-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/30/1072203/20121029/rzqkxhmakk4bokrlm87_-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "i.yimg.jp" + }, + { + ":path": "/images/news/module/md20120709_gsearch.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "content.yieldmanager.edgesuite.net" + }, + { + ":path": "/atoms/71/f8/fb/ee/71f8fbeed96e2ac38d4638d6c6e2ece4.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "headlines.yahoo.co.jp" + }, + { + ":path": "/hl" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/71629/1073618/20121029/tldo4m5hcuajwtl9ebr7-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/3514/1070875/20121102/di3ufilunjw9ul9nrygs-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "amd.c.yimg.jp" + }, + { + ":path": "/im_siggSTQFSGS6B_ulqQXD.kRB.g---x150-y83-q90/amd/20121103-00000687-yom-000-1-thumb.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/30/1072095/20121029/_wzyz3fszhqvouc6tuav-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "content.yieldmanager.edgesuite.net" + }, + { + ":path": "/atoms/23/03/f1/77/2303f17798f0116b59cd53fbb5f89873.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "headlines.yahoo.co.jp" + }, + { + ":path": "/hl" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/71629/1074517/20121029/qym5s_fuonkwfh4vw608-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/71629/1073614/20121029/wnskbirfjfjyqqjwjnx3-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "yjaxc.yahoo.co.jp" + }, + { + ":path": "/oi" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "*/*" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l" + }, + { + "cookie": "B=76j09a189a6h4&b=3&s=0b" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/2959/1085124/20121102/71ewr2thlfq_2yiqyhjw-a.gif" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/30/1072106/20121029/hczia9w6zzi3jskznvxo-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l" + } + ] + }, + { + "headers": [ + { + ":method": "GET" + }, + { + ":scheme": "http" + }, + { + ":authority": "ai.yimg.jp" + }, + { + ":path": "/bdv/26008/1077726/20121029/zuabaglgdswip3wx_faw-a.jpg" + }, + { + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0" + }, + { + "accept": "image/png,image/*;q=0.8,*/*;q=0.5" + }, + { + "accept-language": "en-US,en;q=0.5" + }, + { + "accept-encoding": "gzip, deflate" + }, + { + "connection": "keep-alive" + }, + { + "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_21.json b/jetty-http2/http2-hpack/src/test/resources/data/story_21.json new file mode 100644 index 00000000000..86b67a6a2be --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_21.json @@ -0,0 +1,15422 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "301" + }, + { + "date": "Sat, 03 Nov 2012 13:04:26 GMT" + }, + { + "server": "Server" + }, + { + "location": "http://www.amazon.com/" + }, + { + "content-length": "230" + }, + { + "keep-alive": "timeout=2, max=20" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/html; charset=iso-8859-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "6577" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 23 Oct 2012 17:58:47 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 19 Oct 2012 23:59:58 GMT" + }, + { + "age": "932740" + }, + { + "x-amz-cf-id": "whiC_hNmBgrO48K-Fv1AqlFY-Cig61exld9QXg99v4RwPo9kzfqE9Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 26 Sep 2012 22:18:37 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 25 Sep 2012 20:26:21 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "3249950" + }, + { + "x-amz-cf-id": "LClrkUlr2-9oeIoNwP-CxxGuMmJQguT1mVNFchiptNXT2gkurFa1cw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "3774" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 30 Oct 2012 23:02:44 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 30 Oct 2012 23:02:44 GMT" + }, + { + "age": "309703" + }, + { + "x-amz-cf-id": "0SnGIpF0HloiJDtBSskp0LPclCOdy-cBHBsP3LTUdBy-0l2hmYRW2w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:26 GMT" + }, + { + "server": "Server" + }, + { + "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-amz-id-1": "0HE6SZ5H5Z4Y71SA54J9" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "x-amz-id-2": "MqdgMKxu1H6fgZ4cXY/fMQyxCVupVtmdiA3mTqc2n4+baHA/4MFE3DtVsBH6B4hp" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 11 Sep 2012 13:31:51 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 12 Sep 2008 10:13:34 GMT" + }, + { + "age": "4577556" + }, + { + "x-amz-cf-id": "AvgiZt6QvGiJjVptinxMWssqdE82ATuSxl0D-EfQqkg6iVMBCgJkdQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "7813" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 02 Nov 2012 07:00:01 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 03:41:23 GMT" + }, + { + "age": "108266" + }, + { + "x-amz-cf-id": "C0P4ip7yqOsc3niS_9Bd5ONzppJ1_dduEL7eXeMlCIsohE0Nad0iCw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2503" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 29 Nov 2011 16:46:38 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 02 Jun 2010 17:55:54 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "29362669" + }, + { + "x-amz-cf-id": "T5hInOb6hUOq4NSYTVt8TjsCSGRUHafPxwGkS5jiNGzpLmixDUmWug==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "7441" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 28 Sep 2012 14:59:28 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:01:41 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "3103499" + }, + { + "x-amz-cf-id": "8puqnUMeyh0E9DCrrjWoD5tD9GjqgGyr6aMyg--qLs2ztEb3QIj9HQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4127" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 27 Sep 2012 21:46:40 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 12 Sep 2012 23:45:20 GMT" + }, + { + "age": "3165467" + }, + { + "x-amz-cf-id": "LModLJjBuUU3HjY0zayadcTVs_lDPQK-oIK3WWYJl9ykREzfNIm9Mw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3135" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 16 Sep 2012 13:49:30 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 13 Sep 2012 04:46:34 GMT" + }, + { + "age": "4144497" + }, + { + "x-amz-cf-id": "6OFsf9nPu-D4_yWQy3sINzNayyg6fm625JfZVcPmqYdOicciN0i5rg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3039" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 04 Mar 2012 12:44:05 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Fri, 02 Mar 2012 18:46:04 GMT" + }, + { + "age": "21082822" + }, + { + "x-amz-cf-id": "r7y3D04cQyZW1pY59rhfKoWDuC9yHfp5enkf0y9a6BKaF_6PcDVg7g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4222" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 16 Jul 2012 17:01:48 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 22 Jun 2009 12:02:10 GMT" + }, + { + "age": "9489759" + }, + { + "x-amz-cf-id": "VmOehiu6mDUBpTHylminnvdcSz7Pz3bwA_dNil6iko3qIIKu4pvwQg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1711" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 28 Nov 2011 02:10:41 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 15 Nov 2007 04:25:55 GMT" + }, + { + "age": "29501626" + }, + { + "x-amz-cf-id": "wDhU0erCw0YoyRgAjloixwiytE5IdFT-rCT5ITwxPx5uFgGAv50Y9Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3721" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 18 Nov 2011 22:23:31 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 04 Jan 2011 18:48:20 GMT" + }, + { + "age": "30292856" + }, + { + "x-amz-cf-id": "YXNG-nYMiEVi0gaRGKrCIfNODPvIKOE5L-dzPeXzyYh1LuQTLjvdSA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "24369" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 07:00:00 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 03:43:42 GMT" + }, + { + "age": "21867" + }, + { + "x-amz-cf-id": "2asasoycqewuj5Fwn6w6mjCvOMdZQZLZhNhdl44Yyo1-AI9hQ7bFfg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1216" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 28 Jul 2012 05:05:57 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 28 Feb 2011 18:36:12 GMT" + }, + { + "age": "8495910" + }, + { + "x-amz-cf-id": "6h3O56dcjyQ3aM_m5a8_ir-VgVzDCmcwyIUXFSYcLFIQISyj5Q46vA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "47767" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 14:52:48 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 08 Oct 2012 22:30:55 GMT" + }, + { + "age": "1289499" + }, + { + "x-amz-cf-id": "sO6PqD2yEqaPpl5EvNYnGspKuhuAXsV3jf-Ya1imW1287RLowvVQTQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4613" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 27 Nov 2011 23:44:52 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 21:42:35 GMT" + }, + { + "age": "29510375" + }, + { + "x-amz-cf-id": "qv844DZxuLlk-LGj1-AJNpjz_LOzLR2cGsrHaLRm9jAHtj0ynP66dQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3934" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 00:01:41 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 28 Sep 2012 13:30:37 GMT" + }, + { + "age": "1256566" + }, + { + "x-amz-cf-id": "JW5QyuWGDa5ik9AIEsBmnV6YrytP9At48rtnwWjKkn77rXOj8cx9WA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1344" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 00:59:30 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Wed, 24 Oct 2012 18:51:08 GMT" + }, + { + "age": "43497" + }, + { + "x-amz-cf-id": "IKlxWmc8byHH_FJFiboqtD71dz0H-GkBay3SaG26MwMCXfLft_HgYw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 15 Aug 2012 22:51:53 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=624307871" + }, + { + "expires": "Mon, 16 Aug 2032 07:55:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:27 GMT" + }, + { + "content-length": "5354" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 13:25:50 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630462932" + }, + { + "expires": "Tue, 26 Oct 2032 13:39:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:27 GMT" + }, + { + "content-length": "3658" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 23 Oct 2012 08:00:53 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=629882804" + }, + { + "expires": "Tue, 19 Oct 2032 20:31:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:27 GMT" + }, + { + "content-length": "7632" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "4804" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 21:53:07 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 29 Oct 2012 21:10:04 GMT" + }, + { + "age": "227481" + }, + { + "x-amz-cf-id": "bdyVYgf7boW90khU9D9kSQ4rt8H41h_yufp79zDL_rVA8a9brz2IwA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "148" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 15 Jul 2012 13:57:33 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 01 Aug 2011 23:32:56 GMT" + }, + { + "age": "9587215" + }, + { + "x-amz-cf-id": "Gv6tJh4vJVFIOBxlsPYY_n-mupZYOqsq0_IXHTz6WS89qWAryOKy8g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "356" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 28 Sep 2012 01:43:37 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 21 Jul 2011 20:40:59 GMT" + }, + { + "age": "3151251" + }, + { + "x-amz-cf-id": "A4eNx4xBAu8rDK_SSjVdCoYo59rIc5aBFph1neHeq97ohGyzANNfoA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "6986" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 30 Sep 2012 10:59:49 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:06:32 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "2945079" + }, + { + "x-amz-cf-id": "BCz8ITjlEUNn-tAfee5IQYTwG9afocm__16MmahSICmeqky8tmv-qA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:28 GMT" + }, + { + "server": "Server" + }, + { + "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-amz-id-1": "0HE6SZ5H5Z4Y71SA54J9" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "x-amz-id-2": "MqdgMKxu1H6fgZ4cXY/fMQyxCVupVtmdiA3mTqc2n4+baHA/4MFE3DtVsBH6B4hp" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "x-amzn-requestid": "ffd52343-25b6-11e2-ac17-5765013d7795" + }, + { + "cache-control": "max-age=29030400, public" + }, + { + "content-length": "1140" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "296" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:04:28 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "5728" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 10 Oct 2012 01:33:28 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sat, 22 Oct 2011 00:40:50 GMT" + }, + { + "age": "8903" + }, + { + "x-amz-cf-id": "odznSvAIyfv7NmqZX6A2oTHE_IX5rh889vBaPKfwpg3AMo9k3ScXcA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "6951" + }, + { + "date": "Sat, 03 Nov 2012 13:04:28 GMT" + }, + { + "server": "Server" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "17849" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "ZgdRydvxV2Z5YPfl9vhZZTYWMOX7vl8vIt9RuMTlm258HbYgx1yMhHsXiVTR5T1w" + }, + { + "x-amz-request-id": "135182B51618D297" + }, + { + "date": "Wed, 18 Jul 2012 22:57:25 GMT" + }, + { + "last-modified": "Wed, 18 Jul 2012 22:43:26 GMT" + }, + { + "etag": "\"08b0f3794e1b5e9a927698e159741c50\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "50666" + }, + { + "x-amz-cf-id": "4wcVhu3OEiWfFvYvE3GH5UYO4KY8UpnlLcJRRRqZh0Q1zELrmrAmsA==" + }, + { + "via": "1.0 c33edbf5459a4a44749c2cb5ecdb3fca.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 30 Oct 2012 02:31:02 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630422753" + }, + { + "expires": "Tue, 26 Oct 2032 02:30:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:27 GMT" + }, + { + "content-length": "54217" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1827" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 27 Sep 2012 22:12:58 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 12 Mar 2012 23:57:13 GMT" + }, + { + "age": "3163891" + }, + { + "x-amz-cf-id": "wU_0sJ4VJxKBN-1nsDAgg_KUmfVbpaaGyo7YelU9wE9JmGGGKQ92EQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1134" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 09 Oct 2012 18:09:17 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 12 Mar 2012 23:57:13 GMT" + }, + { + "age": "2141712" + }, + { + "x-amz-cf-id": "SoQLSlLwLn_jdEOyiXGwginYyKphpwUS6-dbQ3wpPqBJIRg6mOrKvQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "636" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 16:53:05 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 02 Jun 2010 22:18:48 GMT" + }, + { + "age": "1195884" + }, + { + "x-amz-cf-id": "twHfjXTW5hFlDA9KoqKVBWXyksHgSNg4Vhy3mstETvyPHr3CpZq6_Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "246" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 26 Jul 2012 10:28:32 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 02 Jun 2010 22:19:30 GMT" + }, + { + "age": "8649357" + }, + { + "x-amz-cf-id": "GuAxInIiaQe4FRi5wBUXvlgCqbiXlqBaFsFj_nccpovWEb1sePoPdQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:29 GMT" + }, + { + "server": "Server" + }, + { + "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-amz-id-1": "05FGR6EKSNDPZCE5TRJQ" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "x-amz-id-2": "Tjab3PJkvWGMyS25sjt7CpJ2clcWTx72Uj5PrdRHrCIku2pHj7RnTwl293ZTfYMX" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "x-amzn-requestid": "ffd52343-25b6-11e2-ac17-5765013d7795" + }, + { + "cache-control": "max-age=29030400, public" + }, + { + "content-length": "1140" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 04 Sep 2012 11:58:23 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=625532809" + }, + { + "expires": "Mon, 30 Aug 2032 12:11:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:29 GMT" + }, + { + "content-length": "656" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 01 Oct 2012 10:33:01 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=628540179" + }, + { + "expires": "Mon, 04 Oct 2032 07:34:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:29 GMT" + }, + { + "content-length": "2251" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 21 Sep 2012 09:55:10 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=627262883" + }, + { + "expires": "Sun, 19 Sep 2032 12:45:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:29 GMT" + }, + { + "content-length": "1098" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 11:48:59 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630506046" + }, + { + "expires": "Wed, 27 Oct 2032 01:38:35 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:29 GMT" + }, + { + "content-length": "1342" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "content-length": "1101" + }, + { + "last-modified": "Mon, 09 Jul 2012 16:40:17 GMT" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "public, max-age=621651328" + }, + { + "expires": "Fri, 16 Jul 2032 13:59:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2424" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 18 Oct 2012 18:56:17 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 07 Oct 2011 03:33:58 GMT" + }, + { + "age": "1361293" + }, + { + "x-amz-cf-id": "MRpSS6BPNijyVanqgR6mydKxGphIrKl9jTmcGgiX2DmcWgVdFwTQ2w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3802" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 08:34:27 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 31 Jan 2012 23:51:01 GMT" + }, + { + "age": "1312203" + }, + { + "x-amz-cf-id": "ohsa-VbEM_mSc8EnpAEXEtU6Nk599gGxk2FtaVe9QKvloqbwSCbxNA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "2" + }, + { + "date": "Sat, 03 Nov 2012 13:04:29 GMT" + }, + { + "nncoection": "close" + }, + { + "server": "Server" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0RMJJXGT1KVEMXX3VSJP" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "NqGNEb/SfkxLIfbOv73h5JBBcLVNGjGLK9GCNJwg5TW2rI8DxuXtaszrL5UZhTYZ" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + }, + { + "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-amz-id-1": "12MZRY3TA9X8CDYHBV5T" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "x-amz-id-2": "mlslIMHpZawNFsGF0x1LVEqrRVG3ckOj+P3RRTLmw7Th6oLI75FjRKiMc9ln/2lK" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "x-amzn-requestid": "ffd52343-25b6-11e2-ac17-5765013d7795" + }, + { + "cache-control": "max-age=29030400, public" + }, + { + "content-length": "1140" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "28988" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 08:13:25 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 23 Jul 2012 20:35:57 GMT" + }, + { + "age": "1227065" + }, + { + "x-amz-cf-id": "mNIt-n16LCJdi8mcEtro9XVeAtGNT2eusOQLsXk2aBoA_LGn9iuGbQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "30231" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 06:32:33 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 00:00:59 GMT" + }, + { + "age": "196317" + }, + { + "x-amz-cf-id": "FIDb9FCQOTap3p4J66TlrId8wIZ_I0Uw8DgL3KGyPEN5FIgqZ4BPpA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "25698" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 28 Sep 2012 10:39:32 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 19 Sep 2012 17:12:28 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "3119098" + }, + { + "x-amz-cf-id": "hKKlixQii0vlb9a_DiDDphY3LEUoIv24q9VfC3UOtpnJV37uLWUpmw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "26311" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 16:56:42 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 15 Oct 2012 20:13:30 GMT" + }, + { + "age": "245268" + }, + { + "x-amz-cf-id": "lpU11IQ1j_7om8_FVILszZ1CEV-8zAg172J2ph8lsbqt3hrfJnS7eQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "34586" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 25 Oct 2012 21:34:09 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 16:33:14 GMT" + }, + { + "age": "747021" + }, + { + "x-amz-cf-id": "DNbatysenX2LUU6xkuO3lGcxhDVX2DG5CzqVUpLHPw-L-eSRtn7_vw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "x-amzn-requestid": "014c3370-25b7-11e2-b46a-73e2a83196ed" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "53" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0RMJJXGT1KVEMXX3VSJP" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "NqGNEb/SfkxLIfbOv73h5JBBcLVNGjGLK9GCNJwg5TW2rI8DxuXtaszrL5UZhTYZ" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/x-icon" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT" + }, + { + "etag": "\"4486-7c5a6340\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "2590" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "35541" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 30 Oct 2012 07:00:01 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 24 Aug 2012 15:19:22 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "367469" + }, + { + "x-amz-cf-id": "kpSB8Aj4s2QcAS66S2b7mB-wlCfwmdJWltC0f0sPcsiYvcEbitBpoQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "31343" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 26 Oct 2012 21:17:40 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 18:24:45 GMT" + }, + { + "age": "661610" + }, + { + "x-amz-cf-id": "i3CTyh6smISPVQ7LqJU5PQ5QUwHdPuZiSswgKhn1iRrMR73x5YQglg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "30919" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 16:31:27 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 23 Aug 2012 22:11:01 GMT" + }, + { + "age": "1283583" + }, + { + "x-amz-cf-id": "m8mt86i5hOEx1AMpRbo6qBzFxqJqTLek8zyWFYjxj2NFT6p2yRbnZw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 22 Oct 2012 15:20:43 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630213450" + }, + { + "expires": "Sat, 23 Oct 2032 16:22:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "content-length": "3978" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Sat, 02 Jun 2012 17:24:51 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=617973507" + }, + { + "expires": "Fri, 04 Jun 2032 00:22:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "content-length": "2352" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 28 Sep 2012 07:05:33 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=628204224" + }, + { + "expires": "Thu, 30 Sep 2032 10:14:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "content-length": "2192" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 29 Oct 2012 00:31:19 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630455624" + }, + { + "expires": "Tue, 26 Oct 2032 11:38:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "content-length": "1783" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "content-length": "3742" + }, + { + "last-modified": "Wed, 13 Jun 2012 19:39:59 GMT" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "public, max-age=618388596" + }, + { + "expires": "Tue, 08 Jun 2032 19:41:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "359" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 23 Jan 2012 18:47:58 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 12 Aug 2011 13:43:43 GMT" + }, + { + "age": "20390" + }, + { + "x-amz-cf-id": "K1hCWmx7ReBxsX55XuAkjHXE0mRsJjI50uNKE5GUBq4SdF4TzxN--A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-id=A7PYmy2fB0qZnFwhmisdExM|t; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "20" + }, + { + "content-type": "text/plain" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "217" + }, + { + "content-type": "text/html;charset=ISO-8859-1" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "158" + }, + { + "content-type": "text/html;charset=ISO-8859-1" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + }, + { + "content-type": "text/html;charset=ISO-8859-1" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "160" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-length": "42" + }, + { + "content-type": "image/gif" + }, + { + "content-location": "http://spe.atdmt.com/images/pixel.gif" + }, + { + "expires": "0" + }, + { + "p3p": "CP=\"NOI DSP COR CUR ADM DEV TAIo PSAo PSDo OUR BUS UNI PUR COM NAV INT DEM STA PRE OTC\"" + }, + { + "set-cookie": "MUID=38CD881268FB628E3D318C1F6BFB6289; expires=Monday, 03-Nov-2014 00:00:00 GMT; path=/; domain=.atdmt.com" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "313" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-length": "42" + }, + { + "content-type": "image/gif" + }, + { + "content-location": "http://spe.atdmt.com/images/pixel.gif" + }, + { + "expires": "0" + }, + { + "p3p": "CP=\"NOI DSP COR CUR ADM DEV TAIo PSAo PSDo OUR BUS UNI PUR COM NAV INT DEM STA PRE OTC\"" + }, + { + "set-cookie": "MUID=39C1843BD7CB679E06238036D4CB670B; expires=Monday, 03-Nov-2014 00:00:00 GMT; path=/; domain=.atdmt.com" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "6951" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "server": "Server" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "17849" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "ZgdRydvxV2Z5YPfl9vhZZTYWMOX7vl8vIt9RuMTlm258HbYgx1yMhHsXiVTR5T1w" + }, + { + "x-amz-request-id": "135182B51618D297" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "last-modified": "Wed, 18 Jul 2012 22:43:26 GMT" + }, + { + "etag": "\"08b0f3794e1b5e9a927698e159741c50\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "50669" + }, + { + "x-amz-cf-id": "UB_lB5ijt678Q2wJ3BJ-U_cVvtSnWAVfUTXcCKhh-QAhIQ9BCb3djQ==" + }, + { + "via": "1.0 c33edbf5459a4a44749c2cb5ecdb3fca.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "x-amzn-requestid": "01a883c0-25b7-11e2-ac1e-e97d81479c85" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "53" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "server": "Server" + }, + { + "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-amz-id-1": "05PW0GT01QWP44EFKF0E" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "x-amz-id-2": "GCho/mJOD51Oufijqw6gqph1/1sIiACGCKJXKh2zpMaDj6u5gA1ggWuscsW3aojI" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "x-amzn-requestid": "ffd52343-25b6-11e2-ac17-5765013d7795" + }, + { + "cache-control": "max-age=29030400, public" + }, + { + "content-length": "1140" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/html" + }, + { + "content-length": "187" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "a+sM7JnK1z8XJALH7//6/PrXIyqStu8OXpFxVoaX6gaWUfZFD47Fr2QQUa/fp7AI" + }, + { + "x-amz-request-id": "1388995ECC503151" + }, + { + "date": "Mon, 22 Oct 2012 17:26:53 GMT" + }, + { + "x-amz-meta-jets3t-original-file-date-iso8601": "2011-11-07T21:33:44.000Z" + }, + { + "x-amz-meta-md5-hash": "a20db430a00109d80184570ec2b5d38e" + }, + { + "cache-control": "max-age=864000" + }, + { + "last-modified": "Tue, 08 Nov 2011 18:37:11 GMT" + }, + { + "etag": "\"a20db430a00109d80184570ec2b5d38e\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "157059" + }, + { + "x-amz-cf-id": "Ls6I3zhLRw-y0K8aIUpki-XaifKyUBIlqjKRtAaQI11Yw135jA8Ahg==" + }, + { + "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/html" + }, + { + "content-length": "232" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "j62Ubwkhgqe/6HUlxy6AgFFF3a9toD+TP5OG4thryUyvAuIRkEPZznTcEkslc2vu" + }, + { + "x-amz-request-id": "D24296DC343E3D4D" + }, + { + "date": "Mon, 22 Oct 2012 17:26:53 GMT" + }, + { + "x-amz-meta-jets3t-original-file-date-iso8601": "2012-08-30T18:01:46.000Z" + }, + { + "x-amz-meta-md5-hash": "ac923fb65b36b7e6df1b85ed9a2eeb25" + }, + { + "cache-control": "max-age=864000" + }, + { + "last-modified": "Thu, 30 Aug 2012 18:02:23 GMT" + }, + { + "etag": "\"ac923fb65b36b7e6df1b85ed9a2eeb25\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "157059" + }, + { + "x-amz-cf-id": "u4HxdeiPj2Z69lQ7aky8PwR3bIL1DI2LZviCrEidCeKNRXIzSU04Hw==" + }, + { + "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/html" + }, + { + "content-length": "246" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "A8pOeFTyzWm76hXU6FfLkQf4c9wZCOf1QF9R4TGkjXEInQJp6farkkg0WB0HfwcK" + }, + { + "x-amz-request-id": "4B032A9637D718D5" + }, + { + "date": "Mon, 22 Oct 2012 17:26:53 GMT" + }, + { + "x-amz-meta-jets3t-original-file-date-iso8601": "2011-11-08T18:38:37.000Z" + }, + { + "x-amz-meta-md5-hash": "abb0183baa0ea995b47dcc0e9972095a" + }, + { + "cache-control": "max-age=864000" + }, + { + "last-modified": "Tue, 08 Nov 2011 18:41:02 GMT" + }, + { + "etag": "\"abb0183baa0ea995b47dcc0e9972095a\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "157059" + }, + { + "x-amz-cf-id": "o02bJWU_jSE66IwLSFs3qnpdALQRgcE53RerA0FNaohnIpayFuIBWg==" + }, + { + "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/html" + }, + { + "content-length": "227" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "9LJz7DXOJVq1v+6jQBPW+PKANy+8UBrktRUpS5ldd7n64fM5B0dvTEVk3oKOAaQj" + }, + { + "x-amz-request-id": "7E12EE38DC5DE3F0" + }, + { + "date": "Fri, 26 Oct 2012 20:55:51 GMT" + }, + { + "x-amz-meta-jets3t-original-file-date-iso8601": "2012-04-11T18:59:01.000Z" + }, + { + "x-amz-meta-md5-hash": "e45b8e1074fb65e447d6d8a91eff8a94" + }, + { + "cache-control": "max-age=864000" + }, + { + "last-modified": "Wed, 11 Apr 2012 18:59:43 GMT" + }, + { + "etag": "\"e45b8e1074fb65e447d6d8a91eff8a94\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "662921" + }, + { + "x-amz-cf-id": "B6N7v4ZLzrFyVRVxNchTyVO2unOzJHIK39q8SJis7c6pWrIOw4rC1Q==" + }, + { + "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/html" + }, + { + "content-length": "236" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "3TVcuu6MQ87em+GdI+9z27lbDxXU5i9H9Zz9GIbm33BZo9vPgIC/AkilBK5tF75Q" + }, + { + "x-amz-request-id": "F105689791C8CFC6" + }, + { + "date": "Fri, 26 Oct 2012 20:55:51 GMT" + }, + { + "x-amz-meta-jets3t-original-file-date-iso8601": "2012-05-18T18:46:04.000Z" + }, + { + "x-amz-meta-md5-hash": "b1178d4fb4111d1058a187cf31c95ab9" + }, + { + "cache-control": "max-age=864000" + }, + { + "last-modified": "Fri, 18 May 2012 18:47:11 GMT" + }, + { + "etag": "\"b1178d4fb4111d1058a187cf31c95ab9\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "662921" + }, + { + "x-amz-cf-id": "sKPhYUyawRrJWnfWsyGL2s3ckBnoapJQYfxvp1W3KVKwMiUhkEK51w==" + }, + { + "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "p3p": "CP=\"CUR ADM OUR NOR STA NID\"" + }, + { + "connection": "close" + }, + { + "location": "http://s.amazon-adsystem.com/ecm3?ex=openx.com&id=40a611fe-06f9-cb74-26a8-7b5edc1205e7" + }, + { + "content-length": "0" + }, + { + "set-cookie": "i=cbdc52da-b3d4-4f79-bc70-3121d006fdfa; version=1; path=/; domain=.openx.net; max-age=63072000;" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "server": "TRP Apache-Coyote/1.1" + }, + { + "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "location": "http://s.amazon-adsystem.com/ecm3?id=&ex=rubiconproject.com&status=no-user-id" + }, + { + "content-length": "0" + }, + { + "cache-control": "private" + }, + { + "set-cookie": "SERVERID=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/" + }, + { + "keep-alive": "timeout=5, max=200" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/plain; charset=UTF-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "10979" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 21 Oct 2012 02:44:45 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 06 Mar 2012 22:20:25 GMT" + }, + { + "age": "1160386" + }, + { + "x-amz-cf-id": "F1Bnl4JS9Kyz-O5cpuXeg0_j5GumDg2Qt1wp0zonzvxPGICjmUSeMg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1526" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 21 Oct 2012 09:00:12 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 15 Jul 2011 19:42:36 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "1137859" + }, + { + "x-amz-cf-id": "JGLRgB6lNjaxDdggNb9JkO58_vLkHmUReZ84GjyLh10FHCjDZ1d15Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "57" + }, + { + "content-type": "image/gif" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "server": "Server" + }, + { + "content-type": "image/gif" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "57" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 20 Apr 2012 10:05:40 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=614707622" + }, + { + "expires": "Tue, 27 Apr 2032 05:11:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:30 GMT" + }, + { + "content-length": "1095" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "11117" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 29 Oct 2012 16:56:50 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 24 Sep 2012 20:44:19 GMT" + }, + { + "age": "418061" + }, + { + "x-amz-cf-id": "5o_BiUaTAD5lYQsK4IV5TzqQ5cWYNQbnt0xLwze5jS-445EERctTFg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "31461" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 17 Oct 2012 18:29:24 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 09 Oct 2012 22:41:15 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "1449307" + }, + { + "x-amz-cf-id": "tw9-4WwNBPYcd_2n5w02SSvFLzYSQr7PgoWnUBoekvj_CAvLUtzicg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 01 Sep 2009 21:16:26 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=618550558" + }, + { + "expires": "Thu, 10 Jun 2032 16:40:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "content-length": "3215" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 20 Oct 2011 08:30:59 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=613322830" + }, + { + "expires": "Sun, 11 Apr 2032 04:31:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "content-length": "3542" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2045" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 16 Jul 2012 05:26:37 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 13 Jul 2011 21:50:54 GMT" + }, + { + "age": "9531474" + }, + { + "x-amz-cf-id": "vjhm9zt0l4ak9rTfcaqoDHHqCVyjy5BT-0EXxKy0Qu1D7GuQLeuwKQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "location": "http://s.amazon-adsystem.com/ecm3?ex=doubleclick.net&google_gid=CAESEDp6zTGnEVOFXTsUTIntlOo&google_cver=1" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "server": "Cookie Matcher" + }, + { + "content-length": "310" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 29 May 2009 20:56:27 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=613357164" + }, + { + "expires": "Sun, 11 Apr 2032 14:03:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "content-length": "739" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "57" + }, + { + "content-type": "image/gif" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "23861" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 09 Oct 2012 23:49:58 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 09 Oct 2012 23:23:03 GMT" + }, + { + "age": "2121273" + }, + { + "x-amz-cf-id": "6igCzs5zDRpfl3uREE8U8b7UsUeKiOXlnR5OwfDF4SRDwMzu4n2Hxw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "expires": "Sun, 04 Nov 2012 06:26:14 GMT" + }, + { + "last-modified": "Wed, 05 Sep 2012 21:17:19 GMT" + }, + { + "etag": "\"19309a1-2b15-e65bd5c0\"" + }, + { + "cache-control": "max-age=172800" + }, + { + "server": "Apache/2.2.3 (Red Hat)" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\", CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\"" + }, + { + "content-length": "3891" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache" + }, + { + "p3p": "policyref=\"http://tag.admeld.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR BUS DSP ALL COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/ecm3?id=bfd291d0-29a4-4e30-a3a2-90bfcce51d8f&ex=admeld.com" + }, + { + "content-length": "275" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "meld_sess=bfd291d0-29a4-4e30-a3a2-90bfcce51d8f;expires=Sun, 05 May 2013 03:59:31 GMT;path=/;domain=tag.admeld.com;" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:32 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "57" + }, + { + "content-type": "image/gif" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "content-length": "9834" + }, + { + "last-modified": "Tue, 14 Aug 2012 08:19:30 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "public, max-age=623720235" + }, + { + "expires": "Mon, 09 Aug 2032 12:41:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 25 Feb 2009 15:49:48 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=580546798" + }, + { + "expires": "Thu, 10 Jun 2032 16:40:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:31 GMT" + }, + { + "content-length": "349" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-lookup": "MISS from cdn-images.amazon.com:10080" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "26111" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 20:57:01 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:57:01 GMT" + }, + { + "age": "144451" + }, + { + "x-amz-cf-id": "14X7FbQwII7W32KG_B6UnQzAAN04K4czIvpQXldrJky1-W_FKI0wsA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "expires": "Mon, 29 Oct 2012 20:03:22 GMT" + }, + { + "last-modified": "Tue, 10 Jul 2012 09:55:27 GMT" + }, + { + "etag": "\"1930a25-22c7-badbe1c0\"" + }, + { + "cache-control": "max-age=90400000, public" + }, + { + "server": "Apache/2.2.3 (Red Hat)" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\", CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\"" + }, + { + "content-length": "2708" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:04:32 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 18 Apr 2012 10:47:18 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=623739489" + }, + { + "expires": "Mon, 09 Aug 2032 18:02:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:32 GMT" + }, + { + "content-length": "2622" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-lookup": "MISS from cdn-images.amazon.com:10080" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:33 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 20:03:15 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 20:03:15 GMT" + }, + { + "etag": "EDAADA0BBD2E54186FB78DECDB80E1E00940A39A" + }, + { + "cache-control": "max-age=283721,public,no-transform,must-revalidate" + }, + { + "x-ocsp-reponder-id": "t8edcaocsp2" + }, + { + "content-length": "471" + }, + { + "connection": "close" + }, + { + "content-type": "application/ocsp-response" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:33 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 16:35:33 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 16:35:33 GMT" + }, + { + "etag": "179CA2EEF2B7FE96BC99C52D47B1A6E9E36FF3A7" + }, + { + "cache-control": "max-age=357659,public,no-transform,must-revalidate" + }, + { + "x-ocsp-reponder-id": "t8edcaocsp2" + }, + { + "content-length": "471" + }, + { + "connection": "close" + }, + { + "content-type": "application/ocsp-response" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:32 GMT" + }, + { + "server": "Apache/2.2.4 (Unix) DAV/2 mod_ssl/2.2.4 OpenSSL/0.9.7a mod_fastcgi/2.4.2" + }, + { + "set-cookie": "KADUSERCOOKIE=A682BC39-E933-4AED-86D3-69AAE2AAD12F; domain=pubmatic.com; expires=Sun, 03-Nov-2013 13:04:32 GMT; path=/" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\"" + }, + { + "connection": "close" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/html" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:33 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "57" + }, + { + "content-type": "image/gif" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:33 GMT" + }, + { + "server": "Apache/2.2.4 (Unix) DAV/2 mod_ssl/2.2.4 OpenSSL/0.9.8e-fips-rhel5 mod_fastcgi/2.4.2" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\"" + }, + { + "connection": "close" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/html" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 22 Oct 2010 19:31:50 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=583595968" + }, + { + "expires": "Mon, 09 Aug 2032 18:02:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:34 GMT" + }, + { + "content-length": "355" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-lookup": "MISS from cdn-images.amazon.com:10080" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 16 Oct 2012 21:06:15 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630485187" + }, + { + "expires": "Tue, 26 Oct 2032 19:51:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:34 GMT" + }, + { + "content-length": "3398" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-lookup": "MISS from cdn-images.amazon.com:10080" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "24345" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 10 Oct 2012 00:37:19 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 09 Oct 2012 23:23:04 GMT" + }, + { + "age": "2118435" + }, + { + "x-amz-cf-id": "tLO5krWbCYmRm9LIjXDN76fC2DJhTSiML3Wx7P5GT_QflWQzjjyLSw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 09 Apr 2012 04:08:58 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=613372173" + }, + { + "expires": "Sun, 11 Apr 2032 18:14:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:34 GMT" + }, + { + "content-length": "3972" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-lookup": "MISS from cdn-images.amazon.com:10080" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "21733" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 21 Oct 2012 01:33:35 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 08 Oct 2012 20:03:10 GMT" + }, + { + "age": "1164660" + }, + { + "x-amz-cf-id": "boy0DjYIiv9QiDUAB5IT03oJw0Oe-TzQq2zaLbbC8-MCS_l6Jrzf5g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 02 Nov 2012 05:55:45 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630608237" + }, + { + "expires": "Thu, 28 Oct 2032 06:01:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:35 GMT" + }, + { + "content-length": "17650" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-lookup": "MISS from cdn-images.amazon.com:10080" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "23996" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 24 Oct 2012 00:39:53 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 08 Oct 2012 16:18:49 GMT" + }, + { + "age": "908682" + }, + { + "x-amz-cf-id": "qC_RVL0YLxYoBvaZ0uqbs2VI6jEgUk34Rk19qpGdS2VsFUS3KkWYMg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "21582" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 18:47:58 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 08 Oct 2012 20:03:11 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "1275397" + }, + { + "x-amz-cf-id": "vHqKStRXJPYsiKzS0tTwY_1XKiks6HvwJGT9UArSlfAs6OnCYHQ7lA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "22139" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 18 Oct 2012 09:05:16 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 08 Oct 2012 20:03:12 GMT" + }, + { + "age": "1396759" + }, + { + "x-amz-cf-id": "3iqSry0i3VhqyuBUo-iRW3UgESSNBQ3lv4YeFtxPi_-Acv46jt6IAw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "849" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 27 Sep 2012 07:28:18 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sat, 16 Jul 2011 00:30:22 GMT" + }, + { + "age": "3216977" + }, + { + "x-amz-cf-id": "jh36SMSXaXj_TeRR9z4Vs8-cbbEoHRGJkz-zWwqnTDkn3mU7WYIILw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 17 Jan 2012 01:18:38 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=613357224" + }, + { + "expires": "Sun, 11 Apr 2032 14:04:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:35 GMT" + }, + { + "content-length": "2305" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-lookup": "MISS from cdn-images.amazon.com:10080" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "2645" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 16 Oct 2012 14:50:28 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 22 Oct 2010 23:53:27 GMT" + }, + { + "age": "1548848" + }, + { + "x-amz-cf-id": "RYwtx5a09etraZHlO8Ut-TcazsQhaIMlHsC_JTzCEXAYeXfmbh0AWA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 22 May 2012 10:05:12 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=623739489" + }, + { + "expires": "Mon, 09 Aug 2032 18:02:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:35 GMT" + }, + { + "content-length": "656" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "590" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 19 Jul 2012 07:06:19 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 06 Oct 2010 20:47:18 GMT" + }, + { + "age": "9266297" + }, + { + "x-amz-cf-id": "jMk_WLA7tRGazvX3ieenZ8uPLkOB1NVjnlmuRGPRPfUGpdfopJWMug==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "618" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 17:16:59 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 14 Sep 2012 15:15:31 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "1280857" + }, + { + "x-amz-cf-id": "gsm-rW_jbFRe2Ne92Oddd13REiBnDzo9k53P59LW-6WZhjFKi2gpcg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "6409" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 06 Oct 2012 05:21:58 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 25 Apr 2012 05:07:39 GMT" + }, + { + "age": "2446958" + }, + { + "x-amz-cf-id": "RenD1oaMDB7WDA0nJBiT78PBjnjUmYU-NT3-eSlLX03q5vM16mQthg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "13915" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 30 Oct 2012 05:57:41 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 29 Oct 2012 19:21:14 GMT" + }, + { + "age": "371215" + }, + { + "x-amz-cf-id": "y-qky_uSUebpzoYKGYMa1lzGeUux4fgnmRhwkgvrXQn78lG5AhfFmA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 22 May 2012 06:41:37 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=621353717" + }, + { + "expires": "Tue, 13 Jul 2032 03:19:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:36 GMT" + }, + { + "content-length": "1580" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4456" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 05:26:53 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 05:26:32 GMT" + }, + { + "age": "286663" + }, + { + "x-amz-cf-id": "QAWFAFoQqqdK6bsebuU01EfGVCwSV_HjtTaLA-hlTAAOA6d4Wsz4wg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2951" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 02 Nov 2012 18:38:41 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 05:26:34 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "66355" + }, + { + "x-amz-cf-id": "Aubb5MuBO28D2I8jIDVYWmI2-8g4Tt0cpl6beMcpVSNTX5gZMv4wgQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4666" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 17:58:34 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 17:58:34 GMT" + }, + { + "age": "155162" + }, + { + "x-amz-cf-id": "OBft3yppuSTyI5o52ZSa5lfbjZWp3ShzF8-dM45Pf0qkJIYh24nQtQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5192" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 16:39:49 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 25 Jul 2012 11:12:38 GMT" + }, + { + "age": "69923" + }, + { + "x-amz-cf-id": "Y6S4ynuqdWWDNdGNvXNtU6fnNBBOoJLWVPdhgnyEnTTMDvI_4XuMzQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5529" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 03:41:12 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 03:15:26 GMT" + }, + { + "age": "293004" + }, + { + "x-amz-cf-id": "ShMwoXym8XNH4S1fFX15TBcjBioYagCJaBprDbqaOtJjOiNkWdeg7g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3629" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 23:15:49 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sat, 23 Jun 2012 21:37:13 GMT" + }, + { + "age": "1259327" + }, + { + "x-amz-cf-id": "HlyMS446sa886uO7DjJyUavWa-mHH0XLcyzUrb49K-G4mkqMbSOsIA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3509" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 25 May 2012 23:03:05 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 24 May 2012 18:35:18 GMT" + }, + { + "age": "13960891" + }, + { + "x-amz-cf-id": "-IZ-Kzdl4oTM776x_-SdI-Sf-rdBE0xeKYvmj2otONB4guu3l0lNsA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4879" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 04:39:14 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 03:14:55 GMT" + }, + { + "age": "289522" + }, + { + "x-amz-cf-id": "UnkzEKXd4DwGvLUL-8-afWzVHMcB4T-tYr9-HLWFRsfbiIvYylwIxA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2809" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 02 Nov 2012 17:24:44 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Tue, 11 Sep 2012 11:41:25 GMT" + }, + { + "age": "70792" + }, + { + "x-amz-cf-id": "ApQSczR7vg5QCdxHZR6hBm1pbl-hGvpxOz6MPp9eCEoBx99I8-atXg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1979" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 18:13:18 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 18:13:18 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "240678" + }, + { + "x-amz-cf-id": "WvvSWSGbGBRHrBf0RFjJ3qJ_o4y9yJuT8SeGDq1dpYvwTANrwyr-Ow==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6942" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 17:58:34 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 01 Nov 2012 17:58:34 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "155162" + }, + { + "x-amz-cf-id": "XA_j3mVwjsJMTgHec3EMMTJ547z0XmIPH8hlMt5tuM1OEe2Kuo_A8g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1854" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 03:41:12 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 03:15:25 GMT" + }, + { + "age": "293004" + }, + { + "x-amz-cf-id": "rPNUJ_0Y4uE0WKLOFZddVt9Pt-15ixc8M9WYFxZcxUq204PEfNtVuw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3661" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 16:20:50 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 11 Sep 2012 21:41:22 GMT" + }, + { + "age": "161026" + }, + { + "x-amz-cf-id": "10WYvTpJNEH0MAP3wne0pXXNE8ZnAI4eVJA3EDPrJ6TF3rv0YJJK_A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2729" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 23:43:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 01 Jun 2011 05:24:35 GMT" + }, + { + "age": "70759" + }, + { + "x-amz-cf-id": "kb2nMqvt29Qj3LdcwS6ww1KobMLzUlJWjzEzfJ49hrIYV9AchOannQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3916" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 02 Nov 2012 17:24:44 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 07 Sep 2012 09:03:37 GMT" + }, + { + "age": "70792" + }, + { + "x-amz-cf-id": "JJZDbMR4RLNK_HVvTbUnNaDilC24pIBmtY7BRd5JkQybHgLPJLr2Bw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2103" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 18:14:15 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 18:14:15 GMT" + }, + { + "age": "240621" + }, + { + "x-amz-cf-id": "AG9h0_9ASRuhaLjhB4fsbvE6ktpeabI5v9S-fSJ_K1SOdr8skxsQ8A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2120" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 18:29:52 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 18:15:06 GMT" + }, + { + "age": "239684" + }, + { + "x-amz-cf-id": "3V9zS2t71NKOHjc-zbQieHw8D15BF88HM5DVQY9j5z7qaxE8JDHbyA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2065" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 02 Nov 2012 17:25:28 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 09 Oct 2012 17:48:33 GMT" + }, + { + "age": "70748" + }, + { + "x-amz-cf-id": "Nkglfv_cx2pdr2EZJF0D475iF5L5LK6Fxcq0dUDPSxCVHftCYtgHng==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2131" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 18:14:15 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 18:14:15 GMT" + }, + { + "age": "240621" + }, + { + "x-amz-cf-id": "Xp7P1ZCF0IjKGtBRruIMsC780cNrxhNJ5960ejB13uXf3su3MHM7PQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2962" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 07:00:00 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 05:49:53 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "194676" + }, + { + "x-amz-cf-id": "peTzFJr516_fOBQY5OC91FWEamWDNAqIh8_l1VUiaqrMRgGupou75w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4626" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 07:00:02 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 05:49:52 GMT" + }, + { + "age": "194674" + }, + { + "x-amz-cf-id": "VMe4jZb7miZ0G-rv3uBPNmdTpYUIYgkj8UaXTHlFZ8sd2SONziLchg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3581" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 17:29:39 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:29:39 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "243297" + }, + { + "x-amz-cf-id": "DQkavQgzFQLKNbG-YUMaAIW1JOadibOwvA_xdhashOIKLfpQuAn2gA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5534" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 05:49:57 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 05:49:53 GMT" + }, + { + "age": "285279" + }, + { + "x-amz-cf-id": "Quota3IS8N_cDOH-5AgNf6IoirJJCjYpEsTfXJKx-QYO8uoPPsgF5Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3336" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 07:03:12 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 07:03:12 GMT" + }, + { + "age": "280884" + }, + { + "x-amz-cf-id": "nKFIlcQrEACy_wNDwvMk7o4wDqwiqg22gTbbx1GgRtKIfeQCY4rAUg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3660" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 07:05:38 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 07:04:35 GMT" + }, + { + "age": "280738" + }, + { + "x-amz-cf-id": "5flYXqijU45smYJrbpa6DyFQK79BKOC75IH_AD_gBLabCf2_f6JJ4w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3631" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 07:03:29 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 07:03:29 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "280867" + }, + { + "x-amz-cf-id": "9zt7Ykby0o5nJUdXmLURwVG97OcVN7UDmlxqqBAr6-kpce1NUZ3vHQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4831" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 31 Oct 2012 07:02:44 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 07:02:44 GMT" + }, + { + "age": "280912" + }, + { + "x-amz-cf-id": "arnnoA4osVhZ9WWxe1rw1kH36LVZpueZhg5Ij7p06zynPPuP_PbhAg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "71" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 21 Oct 2012 07:10:55 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:53:07 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "1144421" + }, + { + "x-amz-cf-id": "otV5h9P0a9-ozjyL5asNyiDOMvE4cnJFvEUCY1qCIkCO1BlYJsF-fQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "4528" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 26 Oct 2012 23:30:10 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sat, 13 Oct 2012 00:03:47 GMT" + }, + { + "age": "653666" + }, + { + "x-amz-cf-id": "zat2zuNOe5PZPMKX9J5IIEc2EvGHW2wIWsGnPPG6NWdX7cWtkKBL3Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "4305" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 02 Nov 2012 19:34:27 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 18:07:44 GMT" + }, + { + "age": "63009" + }, + { + "x-amz-cf-id": "P_0GsZlh-uhXRNgmMVIxDRrsh8CWCBHEX0sNhI9WcxKsR6VpK8qf1A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "8307" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 07:00:07 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 19:02:26 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "194669" + }, + { + "x-amz-cf-id": "_1G9P5_LnBwk_k5A76Q4cs4aOE-c9Y2U6KPOYakVoWIblaFat2Quuw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "3817" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 21:23:14 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 18 Oct 2012 22:25:34 GMT" + }, + { + "age": "1006882" + }, + { + "x-amz-cf-id": "b-rYDPAafNePCeY3rEXSUu_SHu_vhZoVf-W-90RHYbQi7NMrF7IuVw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "14262" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 26 Oct 2012 19:54:19 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 26 Oct 2012 19:43:52 GMT" + }, + { + "age": "666617" + }, + { + "x-amz-cf-id": "DYBg6QCNjA9V6sSGrhw4w4QT--gzcIbkjjJZKjphipyO-cYwRK1p8w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:36 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0D7SZ3NDXXQ10K0Y1P2W" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "Yhw+pyNdxXVfOz+enqEPz5i4xubYpPznUk/Z7jiBcq/rnwK5Kwv0df5Ff+b2ROcL" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT" + }, + { + "etag": "\"4486-7c5a6340\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "2590" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "5639" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 23 Oct 2012 16:30:50 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 23 Oct 2012 16:30:51 GMT" + }, + { + "age": "938026" + }, + { + "x-amz-cf-id": "O6Rt-cRJLPLokVndpOyGdTuWoLI6bPqiRt_TrdmIiYayIHUPbzY__A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "14998" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 30 Oct 2012 20:28:09 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 30 Oct 2012 20:28:09 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "318987" + }, + { + "x-amz-cf-id": "LmtQ4CHgGq-tu05FlE0VnrOXiq0ALsXRzmG89ZFrPGFrzAJOWjQADw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "5391" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 30 Oct 2012 23:27:41 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 19 Oct 2012 17:44:45 GMT" + }, + { + "age": "308215" + }, + { + "x-amz-cf-id": "B9874IgNcW6Dl_iw2J-uxdH_JRYl-xRAXmd-Fx2sDQjm3zOmOAGS6A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "14682" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 00:57:21 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 30 Oct 2012 21:44:15 GMT" + }, + { + "age": "216435" + }, + { + "x-amz-cf-id": "JNivNWPfMlDwvI1crpnpaAtSZ9ynv0-1kJNOR3Kmfy-pFt3R00dHPQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "14468" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 07:00:12 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 24 Oct 2012 03:52:02 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "194664" + }, + { + "x-amz-cf-id": "u_bSf4kdjci5AymBMUSnaNCb7yBkMN4vlmaw6b2yHQaKkeC6bOoqXQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "17329" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 07:00:57 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 20 Apr 2012 19:39:30 GMT" + }, + { + "age": "194619" + }, + { + "x-amz-cf-id": "8NlR_O7HCbbYd6sWYXsaGIxoNNX3kno3ZaIkqqgmHYk3r7P0msD2hA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "5249" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 11 Oct 2012 22:47:04 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 13 Sep 2012 19:26:45 GMT" + }, + { + "age": "1952252" + }, + { + "x-amz-cf-id": "P3861d5dz7qGT13WJVUssV0-8x_VFQt4TtyhgjHZkDhDFHeoBpixcA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 25 Jun 2010 18:22:49 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=623879811" + }, + { + "expires": "Wed, 11 Aug 2032 09:01:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:36 GMT" + }, + { + "content-length": "2903" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 28 Sep 2012 00:00:56 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630492875" + }, + { + "expires": "Tue, 26 Oct 2032 21:59:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:37 GMT" + }, + { + "content-length": "1467" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 30 Oct 2012 03:41:46 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630506567" + }, + { + "expires": "Wed, 27 Oct 2032 01:47:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:37 GMT" + }, + { + "content-length": "4150" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 22 May 2012 06:41:37 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=621353716" + }, + { + "expires": "Tue, 13 Jul 2032 03:19:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:37 GMT" + }, + { + "content-length": "1580" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 17 Jun 2009 18:26:49 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=613395574" + }, + { + "expires": "Mon, 12 Apr 2032 00:44:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:37 GMT" + }, + { + "content-length": "856" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 30 Oct 2012 02:32:26 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630557957" + }, + { + "expires": "Wed, 27 Oct 2032 16:03:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:36 GMT" + }, + { + "content-length": "74964" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "3564" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 21 Oct 2012 19:37:21 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 12 Sep 2012 12:02:28 GMT" + }, + { + "age": "1099637" + }, + { + "x-amz-cf-id": "UnPWM9TK0CYPiYCFO7JpmgG2mEPdetqHfd_sfHtz7tBC7MdT1QthvQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "4267" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 30 Oct 2012 04:55:12 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 12 Oct 2012 19:55:09 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "374966" + }, + { + "x-amz-cf-id": "cjoJQzghJEJQidTuBdcGV7vefvG_4fs26RZ_XZHGp3J47Hsqk_mYqA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 31 Oct 2012 05:23:58 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630506503" + }, + { + "expires": "Wed, 27 Oct 2032 01:46:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:37 GMT" + }, + { + "content-length": "115718" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1104" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 19:46:04 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 02 Jun 2010 22:12:17 GMT" + }, + { + "age": "1271916" + }, + { + "x-amz-cf-id": "CWh3NmGhidrPUirYTJeaMy1q9wfohhNrJcJHsnvLdnXf-hfmvNt_Eg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "6577" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 23 Oct 2012 17:59:58 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 23 Oct 2012 17:58:26 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "2532" + }, + { + "x-amz-cf-id": "h2X5ptCOi7LbCmEDN_-FkzuUX3O9fZGO3nRZaYiuaVmjsZJVea0KlA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "469" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 21 May 2012 18:57:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 17 May 2012 16:40:47 GMT" + }, + { + "age": "76922" + }, + { + "x-amz-cf-id": "cTNh37gW3aRYzh0_ymNAgRrpHgiKNyjCHWwWepii3kfSm2mifkCOuQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1628" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 17 May 2012 00:31:56 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 15 May 2012 05:09:34 GMT" + }, + { + "age": "35944" + }, + { + "x-amz-cf-id": "Lg2DdGTzo_5b8Nxk_htSqW7FB2nLWjG6cKbaOt8zmZY66pVw8K4fCA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "356" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 16 May 2012 19:42:46 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 15 May 2012 05:09:34 GMT" + }, + { + "age": "3065596" + }, + { + "x-amz-cf-id": "1OH_QkiX-oKt7sV0toMi-aqqotKtLvRU2cjdTLewhf5rcVlqqk1ODg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Miss from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:40 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0D7SZ3NDXXQ10K0Y1P2W" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "Yhw+pyNdxXVfOz+enqEPz5i4xubYpPznUk/Z7jiBcq/rnwK5Kwv0df5Ff+b2ROcL" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "application/json" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT" + }, + { + "etag": "\"4486-7c5a6340\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "2590" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "x-amzn-requestid": "070e59c2-25b7-11e2-9647-1185f0fe0569" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:40 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0D7SZ3NDXXQ10K0Y1P2W" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "Yhw+pyNdxXVfOz+enqEPz5i4xubYpPznUk/Z7jiBcq/rnwK5Kwv0df5Ff+b2ROcL" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "application/json" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT" + }, + { + "etag": "\"4486-7c5a6340\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "2590" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "x-amzn-requestid": "0727fc26-25b7-11e2-bb20-cf84a5272b25" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4885" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 07:00:03 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 07 Aug 2012 04:35:28 GMT" + }, + { + "age": "21877" + }, + { + "x-amz-cf-id": "IporfETtFCxA5v41bAp-pDjDCP4cWlKwkoaOGvvvrxS1Mw1yvUBlGQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1543" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 11 Sep 2012 13:00:00 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 02 Jul 2010 18:12:37 GMT" + }, + { + "age": "4579480" + }, + { + "x-amz-cf-id": "-6t8SJvNBh6dZt3rUiRrjIVqnnVJiFbFC-QSFxcqJYuBXrzKAWWdoQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "592" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 20:03:59 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:37:57 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "1011641" + }, + { + "x-amz-cf-id": "8vWzDFif0eREdPSdflEYZlgYAymCWdiDYl8Kv7KC_Fl0ALuKJG_4ag==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1646" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 16 Feb 2012 06:11:58 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 13 Oct 2010 20:47:21 GMT" + }, + { + "age": "22575162" + }, + { + "x-amz-cf-id": "3RdIhQfLO9XOQFa49YXot07-NIDImEld2xoGH4X9880KTfwAGihvfQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "last-modified": "Wed, 31 Oct 2012 22:37:51 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 22:37:51 GMT" + }, + { + "content-type": "application/ocsp-response" + }, + { + "content-transfer-encoding": "binary" + }, + { + "content-length": "1596" + }, + { + "cache-control": "max-age=379990, public, no-transform, must-revalidate" + }, + { + "date": "Sat, 03 Nov 2012 13:04:41 GMT" + }, + { + "nncoection": "close" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "last-modified": "Wed, 31 Oct 2012 20:27:41 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 20:27:41 GMT" + }, + { + "content-type": "application/ocsp-response" + }, + { + "content-transfer-encoding": "binary" + }, + { + "content-length": "1596" + }, + { + "cache-control": "max-age=372180, public, no-transform, must-revalidate" + }, + { + "date": "Sat, 03 Nov 2012 13:04:41 GMT" + }, + { + "nncoection": "close" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:42 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0ZHTZBAADKEZ1K4EGBW6" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "yJRRI8wh/xPuc4C3nBZz5KNXS1OE9OJu63P/XksiIWL9W09cknSsgC8WWr29GiDY" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT" + }, + { + "etag": "\"4486-7c5a6340\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "2590" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "x-amzn-requestid": "0727fc26-25b7-11e2-bb20-cf84a5272b25" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:42 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "1ZH0W43SZ47AMV593QDH" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "wGMRjKh1Pt/o44qHjshIvp7ZIPt2LK8Cze7/o3+/lfgxPUcgTEKCAZBzlDIoLoet" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "452" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:04:42 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "text/html" + }, + { + "content-length": "480" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:04:42 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Wed, 31 Oct 2012 18:39:58 GMT" + }, + { + "date": "Fri, 02 Nov 2012 22:20:44 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 22:20:44 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "43420" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "53038" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1543" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 13:04:42 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 12 Aug 2011 13:43:43 GMT" + }, + { + "age": "20402" + }, + { + "x-amz-cf-id": "6gJoa6bOvFtigUntTCjVHju-EqLbWnHKw6eJPDdiGK6ocghu7-S_cg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 24 May 2012 09:43:11 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=621326683" + }, + { + "expires": "Mon, 12 Jul 2032 19:49:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:42 GMT" + }, + { + "content-length": "4823" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:47 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0DHCSP7QGSTG72H1QPRB" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "iwlAGigQepIxbg6chfZtqXoGGw6vBTgxU/ol+ayO5+ttKg7WcjWBSrPG+7aY5Eey" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:48 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "06NWT8YAYSXDSXHFEBX3" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "+dgTelR5Pvj5ApOpupZ5c4EXyGBnWsp/CtTohBqWXrKuiSIBT+ZSU/92HDHIoBxS" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2393" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 30 Sep 2012 01:55:28 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 15 Dec 2009 04:00:19 GMT" + }, + { + "age": "2977760" + }, + { + "x-amz-cf-id": "iMEciUEJFtmANuUhvSWuNQKwQ56xFPVzicWdjaUIS7KD_SS41vr3pQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "599" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 28 Sep 2012 14:12:09 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:32:16 GMT" + }, + { + "age": "3106359" + }, + { + "x-amz-cf-id": "tN10_L-OYWE-jbnsbpustU_nkePz1Ht2dF12FZfdzo8SDh6xAzABhw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3457" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 30 Oct 2012 16:44:30 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 06 Aug 2012 02:14:57 GMT" + }, + { + "age": "332418" + }, + { + "x-amz-cf-id": "nAZvrqCa80oBwwxAEUWbmmOUITdcLIDdCpFL12zOCAKgSf4n0wfGcQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3174" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 08 Mar 2012 01:24:50 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 15 Oct 2010 14:25:35 GMT" + }, + { + "age": "20777998" + }, + { + "x-amz-cf-id": "o4ZBTBwVKGrCOxAmevzGBdf3GXvw24E_Ibo53uEwUJbXc2EdAiOMyQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "601" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 30 Sep 2012 13:45:07 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:33:44 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "2935181" + }, + { + "x-amz-cf-id": "_ELm77X7wvQxQ8ccnoUS-_woGWJlpaS6DF6N2WkCaQSwNycPUCFD4A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3446" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 05 Jan 2012 14:17:10 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Thu, 10 Feb 2011 01:27:46 GMT" + }, + { + "age": "26174858" + }, + { + "x-amz-cf-id": "-Kkrw4riucQdic2OO_FiGGTwkrKyhvjx0Mcpi0Tz7UmWTD6LAmwHeg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3793" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 26 Oct 2012 19:06:32 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 07 Aug 2012 03:08:01 GMT" + }, + { + "age": "669496" + }, + { + "x-amz-cf-id": "X6dyQ-kDIuminUqGxtG-vyD7eZ70sWXg-ltBtWE0KkdI8OEM-Mpleg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "609" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 25 Sep 2012 16:01:58 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 15:54:14 GMT" + }, + { + "age": "3358970" + }, + { + "x-amz-cf-id": "b_pAd8eX4r8HYc3jV3dhKukKkfwIrYz-zWqHjipfMmhJSE_781h1oQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3653" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 01 Feb 2012 02:46:14 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT" + }, + { + "age": "23883514" + }, + { + "x-amz-cf-id": "bjtvmLGP6K92dIdVA6duj28yhxkrL38nJMkNCptOUGcR-vblR3Dgog==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3268" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 23 Oct 2012 16:12:38 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT" + }, + { + "age": "939130" + }, + { + "x-amz-cf-id": "NjXCi6TD-dhpmdMViBrtzqn_DEt71fFljKydDm_2OCDAPJEMAg5xnA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2974" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 30 Oct 2012 09:47:16 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 03 Apr 2012 10:20:17 GMT" + }, + { + "age": "357452" + }, + { + "x-amz-cf-id": "Z_49skoUilBV6g2nhKUJZO1CTvzkPUHD_SDUxrSh1etd8GS3FknVlQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3246" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 26 Oct 2012 04:05:23 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Tue, 02 Feb 2010 23:26:50 GMT" + }, + { + "age": "723565" + }, + { + "x-amz-cf-id": "0SbSlmo1oQR1EZaPujBcrkn2rp6-JwnKeWPjRJuZmV1Z6bYwy17-7Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3677" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 23:48:37 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:14:18 GMT" + }, + { + "age": "998171" + }, + { + "x-amz-cf-id": "kIXZdAY5Fnpheu46XC3kSBlJD9BzYrmLWTcGFXMEBT4VLXyNpe1SPw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2600" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 14 Dec 2011 20:22:55 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 28 Sep 2011 08:02:37 GMT" + }, + { + "age": "28053713" + }, + { + "x-amz-cf-id": "jdbN9e43yR0jKrrOZUnGZIUGi2GCJHSK3n2VKaDm3XT7Xy-Rj8OqNQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1489" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 18 Jul 2012 14:38:05 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 04 Jun 2010 01:32:52 GMT" + }, + { + "age": "9325603" + }, + { + "x-amz-cf-id": "X3VwQpWnMPHQC7MJRw6T-DaBIBalsbD0mGV4Ng9yHU5gBejjAez0dA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:48 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "1C1W41NW5TYBHBJNXB7G" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "AatuyevJiRUtb6/2d9LbJJ3EZwL4Qi5oAN43fcnZTs+cBfpfR5xhWX4o6c4AFjko" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:48 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "101M70TJ0XKDRA31P9ZW" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "8Q84WjUy4qxnCmekXyK0cOh2MgfmCnF2jlIdsknvZNKQIyUhsXloJp0QYIhPIFFw" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:49 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0R7WZ6VQ04KDQ1RKBSDK" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "iCw5Tdn11Ug6Qn1eOt4uOA+JEPcRxl56zUcXJAWRQ7+nE2ZJ4m5XU7DWbrWSX6Jj" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4760" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 09:19:33 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 27 Jul 2012 14:32:32 GMT" + }, + { + "age": "1309517" + }, + { + "x-amz-cf-id": "wn_k8I4g86z9xU39JO_mi8Znx5qLGm-YEKtqp9bzQUcLva6y9aPWWg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3348" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 14 Sep 2012 14:36:02 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 20 Jul 2012 14:38:01 GMT" + }, + { + "age": "4314528" + }, + { + "x-amz-cf-id": "FEA_NXcSb4YgiTvDGcoQ8YzVOim-T7ZoGwBNe_-tBm3HybITjhj1bw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "587" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 15:34:28 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 15:54:16 GMT" + }, + { + "age": "1200622" + }, + { + "x-amz-cf-id": "vmJhsk3IfjzGGQAAi64eB8PuL0vI87SwHahTEYuBFlmrsmi_dxZ-IA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5691" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 09 Oct 2012 04:35:25 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Thu, 13 Sep 2012 17:48:15 GMT" + }, + { + "age": "2190565" + }, + { + "x-amz-cf-id": "UiucrnKNxdras37pId8z-tCHGNPWFMZJXLOIxPAsl_08EFRty9FxZA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4764" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 16 Oct 2012 16:34:25 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 04 Oct 2012 02:17:34 GMT" + }, + { + "age": "1542625" + }, + { + "x-amz-cf-id": "quvhesbVUpq0D4qHZPiMZU_LBC4xAEbnNL5tNfJoazAENn82wpjOFA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "588" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 28 Sep 2012 12:35:39 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:41:22 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "3112151" + }, + { + "x-amz-cf-id": "RNt3gJPkHWBNRTsYRS0r-qEJUzHeKw0wd8LRUaKmPjRoB_txmvKk0g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3687" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 25 Jul 2012 15:43:46 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 13 Jul 2012 14:50:09 GMT" + }, + { + "age": "8716864" + }, + { + "x-amz-cf-id": "P_VlWy_DI7Q9lOv31mLocJxGBGCO3x_Flg_jDhAwOvSOlHxhfkj4hA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5547" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 21 Mar 2012 20:01:12 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 21 Mar 2012 14:44:09 GMT" + }, + { + "age": "19587818" + }, + { + "x-amz-cf-id": "gVRXsClGSK87EC1y6EX-0j9CO-BL95NF-urXdrKWurV1eDIRau04Cw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4020" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 09:18:15 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sat, 13 Oct 2012 21:42:50 GMT" + }, + { + "age": "1309595" + }, + { + "x-amz-cf-id": "mvpI8qWvGHh__TojWYI7VYmcaawpJ27bnnPJ08ozq7UlLXJiYycA4g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4769" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 08 Oct 2012 21:18:35 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 31 Jul 2012 08:49:37 GMT" + }, + { + "age": "2216775" + }, + { + "x-amz-cf-id": "d8GIZ1IcSWZMBXJ8HsZ_vts4ysREuGFsNrOBA_iB5au7tUOZqueqQQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1759" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 27 Sep 2012 01:27:26 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 12 Jan 2009 18:19:36 GMT" + }, + { + "age": "3238644" + }, + { + "x-amz-cf-id": "bTf74h2ZtQt_I09t6RmrbYg-97o_HtttusNHsh-MGb8gUA51AY7Twg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "17741" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 12 Oct 2012 14:19:15 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Wed, 19 May 2010 09:51:41 GMT" + }, + { + "age": "1896338" + }, + { + "x-amz-cf-id": "UYx91fWWjcOHKIO2wY26UNYf5EQYYW4g5IWOLayy-_r3LBCjQQsV6w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 26 Mar 2012 20:19:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630656332" + }, + { + "expires": "Thu, 28 Oct 2032 19:23:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:53 GMT" + }, + { + "content-length": "2126" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Tue, 17 Jul 2012 05:47:45 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=627946664" + }, + { + "expires": "Mon, 27 Sep 2032 10:42:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:53 GMT" + }, + { + "content-length": "1518" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 04 Nov 2009 06:54:44 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=613395773" + }, + { + "expires": "Mon, 12 Apr 2032 00:47:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:53 GMT" + }, + { + "content-length": "2288" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 21 Sep 2012 07:31:02 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=626993061" + }, + { + "expires": "Thu, 16 Sep 2032 09:49:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:53 GMT" + }, + { + "content-length": "2752" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 29 Oct 2012 04:13:23 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630408896" + }, + { + "expires": "Mon, 25 Oct 2032 22:39:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:53 GMT" + }, + { + "content-length": "18249" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "796" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 12 Oct 2012 10:45:19 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Wed, 19 May 2010 09:51:41 GMT" + }, + { + "age": "1909174" + }, + { + "x-amz-cf-id": "9MHc1JZ7kR7Xm1k_06GjXXBjMfsbYsbpxH549UlaToDw3PtOlOpJng==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:52 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "05Y7M552RGFYHV8MY341" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "oGWKRn1W+jjcnVaAmsQPuDLm0eqlACpITrO3bAh2oWT2VrepfzlHFl5s2S6e8ah5" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "pragma": "no-cache" + }, + { + "x-sap-pg": "photo_display_on_website" + }, + { + "cache-control": "no-cache" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "expires": "-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2358" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 21 Nov 2011 14:41:51 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT" + }, + { + "age": "30061382" + }, + { + "x-amz-cf-id": "rRtoTrePiEQnYeC12h_GTXYCVfIghwtr3bSzq5YQmQ2ZGyWgspVhvQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2343" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 28 Nov 2011 00:30:41 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 06 Apr 2010 23:10:58 GMT" + }, + { + "age": "29507652" + }, + { + "x-amz-cf-id": "47jA2MZ4Sw4DCikN2VyaaWmwTHmqX3rU2MwTeNh7e1Jz_UoUPpYraQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3059" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 05 Jan 2012 13:26:27 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 10 Feb 2011 01:27:46 GMT" + }, + { + "age": "26177906" + }, + { + "x-amz-cf-id": "WYavyIQcFAiZj--Zhj4aZuRfOIHvmeL3UfzvuuRJG_cspyZyEBTZvw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1090" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 06:05:00 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 06 Apr 2010 23:10:58 GMT" + }, + { + "age": "25193" + }, + { + "x-amz-cf-id": "8VDa9TCRS7VKfaAxdyPoMxc3nU5HHd7-ochC_jBjm5Htnl-jkMkuTA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "730" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 25 Jul 2012 12:42:51 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 31 Jan 2011 08:00:09 GMT" + }, + { + "age": "8727722" + }, + { + "x-amz-cf-id": "QrXHFzwiaMq4tNw6xz1x_Fy8OExfQwsb9eYgNg9x5of9ynYhiimfqg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1271" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 05 Jan 2012 19:58:22 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT" + }, + { + "age": "26154391" + }, + { + "x-amz-cf-id": "zfueMiQqfM6t_I7CSioRWzJ6Ja4aCnQfweQZmxivqYZ8HJfnkGedAQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1333" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 08 Feb 2012 22:12:29 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 10 Feb 2011 01:27:46 GMT" + }, + { + "age": "23208744" + }, + { + "x-amz-cf-id": "ELEGmBCM3aCsE_CitSFuw5Z_9oO1nINZ1Td8UGwaW5JQqOgNgrbAgw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1361" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 07 Mar 2012 21:41:49 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Fri, 07 Oct 2011 06:20:36 GMT" + }, + { + "age": "20791384" + }, + { + "x-amz-cf-id": "pOqim5pkNLfn0oKxi7ICFEmFFenUh0PbL_R9Lb9h6TpuGt0tRp4z8Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3006" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 13 Oct 2011 00:59:11 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 02 Feb 2010 23:33:20 GMT" + }, + { + "age": "33480342" + }, + { + "x-amz-cf-id": "G9CB0PE2to9TXhCktQwgI5sW6rlvjeiIaljq43R1hfimZv_emDTQ5Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3051" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 22 Nov 2011 21:04:40 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT" + }, + { + "age": "29952013" + }, + { + "x-amz-cf-id": "8B2pTWiByqir35Y8C9JwI9kCzXLE0qdWzMliO7vI6X4z0IPFb7OJSw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3784" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 24 Jan 2012 22:05:08 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 21 May 2010 10:34:44 GMT" + }, + { + "age": "24505185" + }, + { + "x-amz-cf-id": "iiwiqgcVCWG_cRsMapSsC7zbtuul0T9eNy4NjAklVsbJhZbhbNP0Hw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2439" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 20 Nov 2011 13:48:40 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 28 Sep 2011 08:02:37 GMT" + }, + { + "age": "30150973" + }, + { + "x-amz-cf-id": "N3_BBMhFY33Y_cabN1aZofeaRTYY2qxgxIlyDqqnyzTHoBb-HQQ4kA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3087" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 10:10:03 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Mon, 25 Jul 2011 21:08:27 GMT" + }, + { + "age": "1047291" + }, + { + "x-amz-cf-id": "pUS_TqP5ZtROVGDGuR-eDXw0ijzMiGzziwONZiQwoWOmwMrlTnRUiQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3377" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 12:55:04 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 05 Jun 2009 14:46:00 GMT" + }, + { + "age": "1037390" + }, + { + "x-amz-cf-id": "U8QzlM0myAnVtennCypCEE35AVBn9P7vU8rfVC-qdIV19u_F-61loA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 28 Sep 2012 12:16:12 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:15:32 GMT" + }, + { + "age": "3113322" + }, + { + "x-amz-cf-id": "yRMGD1lIFrzR7iBctL75xllVcgCY4oq5vxpU8vyBYtYIhDG4wgfhhw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2639" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 11 Jan 2011 12:36:42 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 21 Dec 2010 20:23:19 GMT" + }, + { + "age": "57198492" + }, + { + "x-amz-cf-id": "KUP-5JnHht-4Vm9AI5uL23vWqItT_PCAoTXYhS67UcTYyHi9H4qomw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "53" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 29 Sep 2012 16:43:06 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 23:12:42 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "3010908" + }, + { + "x-amz-cf-id": "9nFbAiM9DpxC3cnA__WbfWVECGjZkkgmC6B1r2D6H_pZUeOJpmckKw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1266" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 13 Dec 2011 01:03:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 12 Dec 2011 22:30:22 GMT" + }, + { + "age": "28209671" + }, + { + "x-amz-cf-id": "4XS4NQ5jtAPsXr8uz5LSIhit3YaYLOacfgxTqaJdmgGUSVeVX3L52w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"31-ris0UMaL_SL500_SS100_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "549" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 17 Sep 2012 06:10:41 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 04:41:18 GMT" + }, + { + "age": "4085653" + }, + { + "x-amz-cf-id": "8cM2EbSq2xMoZmAuqaRNnHUXo5fFEkwP993iO66WXR8cQhYdXav_-A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2309" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 00:31:48 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 18 Sep 2012 23:01:43 GMT" + }, + { + "age": "1081986" + }, + { + "x-amz-cf-id": "I_rWsREl-5AOAKtcn3LicFnMAMonpKIxSr1BGia7JpyGrtD-VJlFAw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "4689" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 10 Oct 2012 00:37:12 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 15 Jul 2011 19:43:59 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "2118462" + }, + { + "x-amz-cf-id": "zJr0j4xcaVnqbt7keScwtlVcaVTMpKQyOnG62dfi3bC2Yn7ZUU8hmQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "304" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 24 Aug 2012 23:48:39 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 18 Jul 2008 22:54:46 GMT" + }, + { + "age": "6095775" + }, + { + "x-amz-cf-id": "PKmkuepDkCjjY62A77yQuYuUte5c2Ty-_6DlKmAvhcwzRsHyn5nIrQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "3183" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 27 Sep 2012 03:20:41 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:20:32 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "3231853" + }, + { + "x-amz-cf-id": "OwAw73zfegmW_QHY-kswWa1c-b8oV4xZ-5eevFXbZxfqoKPE6umE4Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "859" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 15:34:26 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Tue, 22 May 2012 07:35:03 GMT" + }, + { + "age": "163828" + }, + { + "x-amz-cf-id": "lfeQCmQ-LTseaf2mLmw-Ec-MgECRsFNyDab6oODONovNp3KBwaWuNQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "904" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 15:34:26 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 21 Apr 2011 09:50:08 GMT" + }, + { + "age": "163828" + }, + { + "x-amz-cf-id": "fx4kuYG47HcKaHNWoFHoUpVuQ9sWagCnJ3Kox-WAsGeI9bLRuIFkZA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"31-ris0UMaL_SL500_SS100_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "988" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 15:34:26 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 11 Apr 2012 09:49:52 GMT" + }, + { + "age": "163828" + }, + { + "x-amz-cf-id": "pdz_b69t7pq2FxRxED3J9qfLWu_VlLnSgt3UkrYI2IsWgh0cxAcbRg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "7477" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 13:03:42 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:06:13 GMT" + }, + { + "age": "1296072" + }, + { + "x-amz-cf-id": "IpXkwhJGWUHRMnyRAQVIxqffI1_ZEyW-nzUYrSWrfr8R_Y1uuGRCCQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "702" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 14 Sep 2012 15:53:26 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 12 Oct 2011 01:31:30 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "4309888" + }, + { + "x-amz-cf-id": "HsG6bJczHwzkieHglmFzE2QCmzLxTaLPXXnAy-N55tzbuvrtZRCzCw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "7983" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 12:29:27 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 15 Jul 2011 19:44:12 GMT" + }, + { + "age": "1298127" + }, + { + "x-amz-cf-id": "sCXON_3fv6WubL7uLSJaIqpVlCgjIetJyv1h_hMdF4cY17dhW5AtuQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "21587" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 07:42:49 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 27 Sep 2012 18:42:30 GMT" + }, + { + "age": "1315325" + }, + { + "x-amz-cf-id": "T9aSuzcFAaMOSl0BfGK1RZtk2bHJRFveb6whI8ExXPmes7P1gEIr_g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "14808" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 14 Sep 2012 19:42:20 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sat, 02 Jun 2012 16:25:51 GMT" + }, + { + "age": "4296154" + }, + { + "x-amz-cf-id": "0V2zXn_NrH1y0_eQiJhavI_iThDjEBl3W8rbz6WK2bL14yhUFFMzMg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "929" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 15:34:26 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sun, 20 Jun 2010 09:46:10 GMT" + }, + { + "age": "163828" + }, + { + "x-amz-cf-id": "kSSVSJhWVu77d7bZr26ow7tGxAtxQIJKxzBSnMTb-BvsXBOXCVvmrQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "170" + }, + { + "content-type": "text/html;charset=ISO-8859-1" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "content-type": "text/html" + }, + { + "content-length": "246" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "A8pOeFTyzWm76hXU6FfLkQf4c9wZCOf1QF9R4TGkjXEInQJp6farkkg0WB0HfwcK" + }, + { + "x-amz-request-id": "4B032A9637D718D5" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "x-amz-meta-jets3t-original-file-date-iso8601": "2011-11-08T18:38:37.000Z" + }, + { + "x-amz-meta-md5-hash": "abb0183baa0ea995b47dcc0e9972095a" + }, + { + "cache-control": "max-age=864000" + }, + { + "last-modified": "Thu, 30 Aug 2012 18:02:23 GMT" + }, + { + "etag": "\"ac923fb65b36b7e6df1b85ed9a2eeb25\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "157082" + }, + { + "x-amz-cf-id": "QZJcXJG7Ji8wu-0D789ZbWAnaHnVN-XBUkupFYbHTmHhHcHrJq7P9Q==" + }, + { + "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "451" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 05 Oct 2012 15:21:37 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=628223582" + }, + { + "expires": "Thu, 30 Sep 2032 15:37:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "content-length": "856" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 29 Oct 2012 04:12:21 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630383568" + }, + { + "expires": "Mon, 25 Oct 2032 15:37:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "content-length": "6979" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 17 Oct 2012 16:08:26 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=629262241" + }, + { + "expires": "Tue, 12 Oct 2032 16:08:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "content-length": "1860" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Mon, 18 May 2009 10:07:44 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=580533835" + }, + { + "expires": "Mon, 27 Sep 2032 10:42:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "content-length": "810" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-lookup": "MISS from cdn-images.amazon.com:10080" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "text/html" + }, + { + "content-length": "516" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache" + }, + { + "p3p": "policyref=\"http://tag.admeld.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR BUS DSP ALL COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/ecm3?id=bfd291d0-29a4-4e30-a3a2-90bfcce51d8f&ex=admeld.com" + }, + { + "content-length": "275" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "meld_sess=bfd291d0-29a4-4e30-a3a2-90bfcce51d8f;expires=Sun, 05 May 2013 03:59:31 GMT;path=/;domain=tag.admeld.com;" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Thu, 27 Sep 2012 18:22:05 GMT" + }, + { + "date": "Fri, 02 Nov 2012 14:49:26 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:49:26 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "25380" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "80128" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\"" + }, + { + "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t" + }, + { + "nncoection": "close" + }, + { + "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "57" + }, + { + "content-type": "image/gif" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 28 Sep 2012 08:55:13 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=628633148" + }, + { + "expires": "Tue, 05 Oct 2032 09:24:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "content-length": "16588" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 11 Apr 2012 19:05:24 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=617190640" + }, + { + "expires": "Tue, 25 May 2032 22:55:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "content-length": "10742" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 25 May 2012 04:46:13 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=621621842" + }, + { + "expires": "Fri, 16 Jul 2032 05:48:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:55 GMT" + }, + { + "content-length": "3960" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 26 Oct 2012 09:03:20 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=630485970" + }, + { + "expires": "Tue, 26 Oct 2032 20:04:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:54 GMT" + }, + { + "content-length": "14019" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:56 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "16ZMB88V50KWWQXFQZNR" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "0PU9VNtv9/YHthxuwDwGQDz7kHY8GLhrhbQs/A0BbIf1y/GiCONyJttmltEgnDaZ" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:56 GMT" + }, + { + "x-amzn-requestid": "10a7eef8-25b7-11e2-a2e0-8bdc8a85b675" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "53" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:56 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "16KH0V157G0TXXQVTR1Z" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "6Hy72ZQh4+twTqX90DijzRdHDpTv81nJLyxFZMBbjNHkb8qZfDO7y4+75uITFMjm" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "2212" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 27 Sep 2012 04:09:18 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 03 Aug 2011 20:37:32 GMT" + }, + { + "age": "3228938" + }, + { + "x-amz-cf-id": "e_uegUCHnyG0CG1xWLrNCiBH1sC8uTUlb-e31fTCz2013GXiBQpv3g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1658" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 16 May 2012 17:46:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT" + }, + { + "age": "14757493" + }, + { + "x-amz-cf-id": "rjUV7bECb3foXt-4i01sG21mlvMgo9nOu7EtcMeIYzyJSWWqNNlDOw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "16364" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 14 Dec 2011 03:17:38 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Fri, 04 Nov 2011 23:48:42 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "28115238" + }, + { + "x-amz-cf-id": "I6W0oRiMtuRDCDZetJr8DtOxr0nMh8QpK29mcgE2eMGEw69ogMaPdg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 13 Jul 2011 17:18:50 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=616029616" + }, + { + "expires": "Wed, 12 May 2032 12:25:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:04:56 GMT" + }, + { + "content-length": "594" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:56 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0X3NVRPASEGRWVCHH1H3" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "+dgTelR5Pvj5ApOpupZ5c4EXyGBnWsp/CtTohBqWXrKuiSIBT+ZSU/92HDHIoBxS" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2902" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 27 Oct 2012 23:34:12 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 20 Jul 2012 15:59:40 GMT" + }, + { + "age": "567044" + }, + { + "x-amz-cf-id": "bYLWczW4h_oqRLXSyZdMo3kjSsqUZNWoGXrVLgvaIVqM8SXrlaPicA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3155" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 26 Jul 2012 09:16:33 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 19 Jul 2012 17:10:12 GMT" + }, + { + "age": "8653703" + }, + { + "x-amz-cf-id": "pxFBejzs4oRgmqxYc2s6mbS_QBknibmyPLQGd8Ejv-8cWl04HQGPtA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3536" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 27 May 2012 08:44:57 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 19 May 2011 14:46:28 GMT" + }, + { + "age": "13839599" + }, + { + "x-amz-cf-id": "vToxkdVmSZQS0V3iRZM-gCcaadczMLYZw_REFYGTBUn-HP5HfdAeDA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3143" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 06 Aug 2012 15:53:39 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 06 Aug 2012 03:38:02 GMT" + }, + { + "age": "7679477" + }, + { + "x-amz-cf-id": "752wgDaFeaq4IQjicHeqyUiLYIjEjsca-nvc2LB2o4jOXMT99M6E2g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3209" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 28 Feb 2012 22:53:21 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 21 Oct 2010 19:52:40 GMT" + }, + { + "age": "21478295" + }, + { + "x-amz-cf-id": "UDgO86Lg7vsbRr_HLz0bT_G-fu7CRAkkBmD_NFdclHEzx1CJpRhtKw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"31-ris0UMaL_SL500_SS100_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3210" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 27 Oct 2012 23:45:01 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Fri, 20 Jul 2012 15:59:43 GMT" + }, + { + "age": "566395" + }, + { + "x-amz-cf-id": "rEUppa210byJyTItTaRQ2r-jhwUwD4c2CKORz2AGJaLhjCZ_LQ2w9w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:56 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0ESJ91CM6R89TGWH3QJG" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "Mg+wYQrytsBDnHHKyZlGNrkR5GzVMXvkIuJkR86aYslzZP5CJX/EEO5A8c1v2Jk4" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "21282" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 01 Nov 2012 21:09:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 21:09:31 GMT" + }, + { + "age": "143714" + }, + { + "x-amz-cf-id": "jFqxNpOKI6HWPqTs3raLIRgnJcu3GReFRL3MjibUt9APw7R9CfzNqQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "439" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 19:18:25 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:16:17 GMT" + }, + { + "age": "1187193" + }, + { + "x-amz-cf-id": "5en8vtO00oTNRx5jsyJYxwuPMEVufg38JPIk7uytbZiFN77vUtBibg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:57 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "1AB4PH2A91QH3YJJ2WCZ" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "V5wX099kS85XeVk46pZgvH7cjgKx1WawnTJkqYth5ykinf4em6ZqgNlZk9K/lPby" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "67" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 05:50:27 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:16:14 GMT" + }, + { + "age": "1062871" + }, + { + "x-amz-cf-id": "eIpkgqRGkyaTW4PSLscvrasxuDsM3f4NIrPYv6VI1sZt_IgixOKN_A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "861" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 07:26:29 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Sat, 24 Nov 2007 03:04:01 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "1316309" + }, + { + "x-amz-cf-id": "5MBwLvJE3E5vg0khYEnuWX6RGzCOtyfFmYYy2nuztIayL9O0paE0oA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 23 Oct 2012 09:12:37 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 04 Jun 2010 01:44:17 GMT" + }, + { + "age": "964341" + }, + { + "x-amz-cf-id": "W5ENbtcrY4pVK3r7ND94JJHXcEjjBccP7Q77zOSiZQUgWtPBn75lHw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1598" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 15:51:07 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:16:29 GMT" + }, + { + "age": "1199631" + }, + { + "x-amz-cf-id": "nFYTABAConMh8T_fXHANG9_r3FjyUfnSBWjxeb2GqJKtgi_mNRIXMw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1657" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 25 Sep 2012 17:28:50 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:16:30 GMT" + }, + { + "age": "3353768" + }, + { + "x-amz-cf-id": "ssIfXXDbBp8rP_142eUVOboNUYX4Iood5RH_Qe9W7wP1xbkZp9MChw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3013" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 28 Nov 2011 22:24:05 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT" + }, + { + "age": "29428853" + }, + { + "x-amz-cf-id": "vO0R09hZC6TnyhMNTV9jEegb2DgNmH-Z1KaQiyeSbsYm8eoBtHUnDw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "455" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "text/html" + }, + { + "content-length": "2522" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + }, + { + "server": "Apache" + }, + { + "dl_s": "a104" + }, + { + "x-host": "a104 D=1922" + }, + { + "p3p": "CP=\"ALL DSP COR PSAa PSDa OUR IND COM NAV INT LOC OTC\", policyref=\"http://ch.questionmarket.com/w3c/audit2007/p3p_DynamicLogic.xml\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "558" + }, + { + "keep-alive": "timeout=120, max=934" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/html; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + }, + { + "server": "Apache" + }, + { + "dl_s": "a104" + }, + { + "x-host": "a103 D=213" + }, + { + "p3p": "CP=\"ALL DSP COR PSAa PSDa OUR IND COM NAV INT LOC OTC\", policyref=\"http://ch.questionmarket.com/w3c/audit2007/p3p_DynamicLogic.xml\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "78" + }, + { + "keep-alive": "timeout=120, max=941" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "expires": "Mon, 26 Jul 1997 05:00:00 GMT" + }, + { + "cache-control": "post-check=0, pre-check=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "PL=_974702-1-83324420; expires=Sun, 03-Nov-2013 13:04:58 GMT; path=/; domain=.questionmarket.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Wed, 17 Oct 2012 17:29:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 05:34:15 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 05:34:15 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "27737" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "27043" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + }, + { + "server": "Apache" + }, + { + "dl_s": "a212" + }, + { + "x-host": "a212 D=715" + }, + { + "p3p": "CP=\"ALL DSP COR PSAa PSDa OUR IND COM NAV INT LOC OTC\", policyref=\"http://ch.questionmarket.com/w3c/audit2007/p3p_DynamicLogic.xml\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "43" + }, + { + "keep-alive": "timeout=120, max=973" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Mon, 26 Jul 1997 05:00:00 GMT" + }, + { + "cache-control": "post-check=0, pre-check=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "ES=974702-1d5qN-0; expires=Wed, 25-Dec-2013 05:04:58 GMT; path=/; domain=.questionmarket.com;" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + }, + { + "x-amzn-requestid": "123b3889-25b7-11e2-8af6-a1b44f97a3ae" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "53" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "1ZP9F4EGXPG1W1PYCNJK" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "AsL0eWMF3+3wScCyR0bGR31dSLss9n05o3uERrVw6pReE9DgHJ1jKFUl9eThTjRS" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "168BW4BHQH0ZXM7FXMPB" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "cEL12N93+m4WoEqFtPIfCFUi+syrhK4ihYi/vQREHqBRscgh343Rj/z+yvBSU/1C" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:04:58 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "1PF1RSF1KPZFT8AG8QH3" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "BMEF9l9idgW7J6L5kAVCmgL1L1VX3ONDIY4c/R7+/waDULftLKfFOhjdf5bX9Jgw" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "76" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 25 Sep 2012 13:31:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 15:53:50 GMT" + }, + { + "age": "3367996" + }, + { + "x-amz-cf-id": "ecrxOwZyLIYoOI7n1HZdjAnEynOb8rnSjf9oMBvu9l-mcg-DvsQ5tA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2953" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 14 Oct 2012 20:13:59 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Fri, 18 Mar 2011 23:50:26 GMT" + }, + { + "age": "1702260" + }, + { + "x-amz-cf-id": "RRnk1cdyHejHw9mprrW3eHhVJDtMgC2-2Z_Ozk1TtfyHQbMGDRM1gQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2908" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 00:29:01 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT" + }, + { + "age": "45358" + }, + { + "x-amz-cf-id": "dVVqpxaUvghScp5L3V8knNH7yD0rPX4f2QIUqHQG7hWgDw29J2DGyQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2684" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 29 Oct 2012 09:50:03 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 02 Feb 2010 23:26:50 GMT" + }, + { + "age": "443696" + }, + { + "x-amz-cf-id": "PlD1_xjVuo-YCz7_Za4wyP6LFVnojIw0t9xjXHByHBqF2ZeqI4b_qg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"31-ris0UMaL_SL500_SS100_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "879" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 08 Jul 2012 02:35:34 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT" + }, + { + "age": "10232965" + }, + { + "x-amz-cf-id": "NFgWbhPAIPS6Aa_OA1MZi4RJV38Eh2JztiuONINXzMa0bG62le6jyA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "829" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 29 Nov 2011 15:46:34 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:49 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "29366305" + }, + { + "x-amz-cf-id": "09OGcA01CtEV2DWxFMbKMdNmD6Wr6zUzXg6LlkVtCG84Y07dTLSY0Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "874" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 17:41:46 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT" + }, + { + "age": "1192993" + }, + { + "x-amz-cf-id": "rwvtxrU_8yM4vEsn3LxI68PMeCTNAaI2pID_hvPOaXhJAUXpLcUqOQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "839" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 28 Jul 2012 16:53:55 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT" + }, + { + "age": "8453464" + }, + { + "x-amz-cf-id": "jK_V3T8gBhnVX6aGpizNe84I03zSajHOTGC01MnF2N-ZKUFTuuznfg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "873" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 02 Oct 2012 10:07:50 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "2775429" + }, + { + "x-amz-cf-id": "zP8uDh7oW4qGktFpCJQlKyzDvuaUlw8SfQPZeV2OLAF_FolwTs7PYA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "839" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 04 Oct 2012 03:38:14 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT" + }, + { + "age": "2626005" + }, + { + "x-amz-cf-id": "zCUT7P4ddAsA_5EOdXS-ecWSi3Caf1GD9wdw37lzeKfQj2j9AmHUiQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "829" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 18 Feb 2012 00:35:57 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:46 GMT" + }, + { + "age": "22422542" + }, + { + "x-amz-cf-id": "QKTCegDFqVr3XC8HIuieCb-HlLFpsf1vJJyDKhTn9DFbJiLWVXQjLQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "874" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sun, 29 Jul 2012 00:33:38 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:47 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "8425881" + }, + { + "x-amz-cf-id": "FQmsZuwjmRdgwUM5HxTx27tY2H27QOrbg1DJdNz_RrAOa991o5Lvyw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:05:01 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "1KF6CJF0ZA3T90MCGE8X" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "EhBekXVsIWcz6GtFV9/VWJHMzQoVZUur+CK0EG1dAElJjqTWpGnJuKNs84/dLZ0q" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "394" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 23 Oct 2012 16:46:08 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:46:54 GMT" + }, + { + "age": "937134" + }, + { + "x-amz-cf-id": "L9oihLkhCsGUlU-3jqFLwWX3TyuBQLcp_cHchbBiCmtUA736X8Kphg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "627" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 11 Oct 2012 14:33:21 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:15:44 GMT" + }, + { + "age": "1981901" + }, + { + "x-amz-cf-id": "7ml4lF66qQTzIXFECW3ocZ5nG9vHHfuYDmXpdeBjLVSaQQolCys92A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "621" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 10 Oct 2012 11:21:25 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:15:46 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "2079817" + }, + { + "x-amz-cf-id": "CoLcmSXF2suFL6QBnOjjLxEUhf72VKlrplyC4RYJlfNREf6-Xi0pXw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2358" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 29 Nov 2011 01:52:38 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT" + }, + { + "age": "29416344" + }, + { + "x-amz-cf-id": "dRi8YsVC5rJM48lwap3Mh06QHVr9w6Oq0Pfg31QRRKiDl1QSIT3zdg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1594" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 10:14:19 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:15:59 GMT" + }, + { + "age": "1219843" + }, + { + "x-amz-cf-id": "1biuu9U97pslYVYAmMFhrwSwOBYVwXiLgwm1MRKI7_h7l2zmYZZEaQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 26 Sep 2012 22:18:37 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 25 Sep 2012 20:26:21 GMT" + }, + { + "age": "3249985" + }, + { + "x-amz-cf-id": "fX317kpOFNd5ZTVD5dUMrmSEeYRzqm4WpyDuKNG28yJ4O9eAvvazUw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1061" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 19 Oct 2012 11:04:19 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:18:05 GMT" + }, + { + "age": "1303243" + }, + { + "x-amz-cf-id": "mAtXqkAkC4DjophBzYEW5S6QprX5KyDZpPzyK9EozCLiukdFrBze5A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "850" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 19 Nov 2011 02:02:32 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:12:52 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "30279750" + }, + { + "x-amz-cf-id": "V9zouqOby7zTdw8N1UFD-7MjNT6Is1zC6qGyOi0cvSwTqMJZ1Qkygw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2561" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 01:47:15 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT" + }, + { + "age": "1077467" + }, + { + "x-amz-cf-id": "S275mzRyfiEZwFTcPfyW0eoYH91UX_599Ev_ECgM6b_xOLfjspcbHg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"31-ris0UMaL_SL500_SS100_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "564" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 29 Nov 2011 11:54:46 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 04 Jun 2010 01:27:32 GMT" + }, + { + "age": "29380216" + }, + { + "x-amz-cf-id": "R7S8on0vdk1HXxrim-2c2Zh8aNdO6mf4C0WS3tKHegaM2jWsiM5epQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1698" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 29 Nov 2011 12:21:20 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:03:45 GMT" + }, + { + "age": "29378622" + }, + { + "x-amz-cf-id": "YvMqD5UqqFKzy1f2mFcHqX7aM_4HxOmRkYus-RhWfCdy_pqhPAEz_g==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "558" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 11:34:34 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Fri, 04 Jun 2010 01:27:17 GMT" + }, + { + "age": "1215028" + }, + { + "x-amz-cf-id": "cVa44QM2u8IAuUF9QEfpfnoTg8a0J18iQn7wd2DQr-jo-fY8BpiHkQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "2268" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 28 Jul 2012 02:30:22 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:00:18 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "8505280" + }, + { + "x-amz-cf-id": "22Ju-KfgdJeRvZSlX5DsdLObbhPEZeBSd4Gc72ZIaWMiVqmbMkB3Bg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "161" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 25 Sep 2012 20:28:46 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:15:25 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "3342976" + }, + { + "x-amz-cf-id": "qmBPDk2JKVaJRpv7A4mhguHOgSAQ224UfofPNOhYc7AXsZ28LFXM-Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1567" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 29 Sep 2012 12:18:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:14:03 GMT" + }, + { + "age": "3026779" + }, + { + "x-amz-cf-id": "9apayreRLqLNv5SP9KNS5EuSvY5sPVDHoDgblKHgUdkUCoUDFfPCbw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "2075" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 08 Feb 2012 03:25:50 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:19:09 GMT" + }, + { + "age": "23276352" + }, + { + "x-amz-cf-id": "x7eg4fYYkTWpaWFE4nN7BtaqRyiZfNva-voci7p3Xzbfipq19svpKQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1703" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 29 Nov 2011 09:32:04 GMT" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:14:39 GMT" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "age": "29388778" + }, + { + "x-amz-cf-id": "Sud7TM_0UEovovJxWwSbgeoYTXcAYAv14GhdR63hJZOjeBUYsvtKqQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"01-XuHrwcHL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "2601" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 25 Jul 2012 12:53:34 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:17:36 GMT" + }, + { + "age": "8727088" + }, + { + "x-amz-cf-id": "mAk0OO6evBoCPjFxnJqirH_8vom2gwHEBysCZcqQfQejl1rp3OGD1Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1581" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 22 Oct 2012 11:57:50 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:13:01 GMT" + }, + { + "age": "1040832" + }, + { + "x-amz-cf-id": "Dib_HmcmgtWNGzNtGv3F6ZAXixIagykEiamEBmt2obULi0G_yrbohw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "cneonction": "close" + }, + { + "etag": "\"01+KP3cIDVL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "44" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 20 Oct 2012 02:45:35 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 16:13:49 GMT" + }, + { + "age": "1246767" + }, + { + "x-amz-cf-id": "wjm3efkQaATVWVoZIxXYwJ9h7_UJVQWBeywk_XevnjWO-aG5dXU1uw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Thu, 12 Mar 2009 22:20:15 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=613385389" + }, + { + "expires": "Sun, 11 Apr 2032 21:54:51 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:05:02 GMT" + }, + { + "content-length": "1167" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"11Z3ZviGhqL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:05:02 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0N0ET7DXR0Z0S958XDT2" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "rVbwKM7uj9c8KPLYmRAVt4kYRdMGzqE9h6Tyc+UcXD6y0h6n5t1Qps2dG4l0erjn" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1419" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 21 Nov 2011 14:19:01 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT" + }, + { + "age": "30062762" + }, + { + "x-amz-cf-id": "V720Rh4VXwLpavgc0gzogCAvcfu8eju-6aTUgkZ0KVqt2Dmee6LRbA==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3603" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 06:00:11 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Tue, 06 Apr 2010 23:10:58 GMT" + }, + { + "age": "25492" + }, + { + "x-amz-cf-id": "fQb0nipMtXJuYbIZySKBDRsrklJuv7qAkK8XsAxNdlaxuu3_Nb882A==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "610" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 10 Oct 2012 05:09:08 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 01:30:08 GMT" + }, + { + "age": "2102155" + }, + { + "x-amz-cf-id": "CaXyn6Of0tMpboI2JSReSog7OZegmXSk2HeG_0TZ-GXKneON61wt4Q==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"11+dlfeUrBL#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6063" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 28 Sep 2010 14:19:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Sun, 23 May 2010 07:31:32 GMT" + }, + { + "age": "66264320" + }, + { + "x-amz-cf-id": "Xi5psl_5u_FA8F_cxp1Bgg5JQqekzjzXubyxkq6OioH5vJa_xpl7bg==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"31-ris0UMaL_SL500_SS100_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3808" + }, + { + "connection": "keep-alive" + }, + { + "date": "Mon, 23 Jan 2012 20:55:29 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 28 Sep 2011 08:02:37 GMT" + }, + { + "age": "24595774" + }, + { + "x-amz-cf-id": "YCExo8QCW6i8b43rK1WKdbqGi4BBr67tDQvHKeByUOjFZWkYcGmSVw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4743" + }, + { + "connection": "keep-alive" + }, + { + "date": "Thu, 16 Feb 2012 18:43:39 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT" + }, + { + "age": "22530084" + }, + { + "x-amz-cf-id": "f-ZNWJJlfQWW0yKzQd7uCRUJaMBxf_uM7iH1fbKBNdQQggwy-fMhMQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5433" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 10 Apr 2012 03:22:11 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Wed, 15 Feb 2012 16:43:09 GMT" + }, + { + "age": "17919772" + }, + { + "x-amz-cf-id": "d_if579P0cd1V3nzUXiXXtDTylQLMz1X-zUPk2ry79G_nUYX-N0rAQ==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4449" + }, + { + "connection": "keep-alive" + }, + { + "date": "Fri, 23 Mar 2012 00:45:43 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "etag": "\"41YZLkI+UsL_SL135_#1\"" + }, + { + "last-modified": "Fri, 09 Sep 2011 07:00:28 GMT" + }, + { + "age": "19484360" + }, + { + "x-amz-cf-id": "XHbZSMpsPMFYPGHelyqQvYo133-6UF8nzLJrfmuubfb8md_c3wKN8w==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4065" + }, + { + "connection": "keep-alive" + }, + { + "date": "Tue, 25 Sep 2012 13:07:27 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Thu, 04 Feb 2010 16:43:55 GMT" + }, + { + "age": "3369456" + }, + { + "x-amz-cf-id": "cqvYtZEgzgfwS7oAvqOkuzRizhSe9arLcRGaP5nnF2izwecHSwS-Cw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"31-ris0UMaL_SL500_SS100_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4778" + }, + { + "connection": "keep-alive" + }, + { + "date": "Wed, 14 Sep 2011 17:50:19 GMT" + }, + { + "server": "Server" + }, + { + "cache-control": "max-age=630720000,public" + }, + { + "expires": "Wed, 18 May 2033 03:33:20 GMT" + }, + { + "last-modified": "Mon, 24 Aug 2009 16:48:22 GMT" + }, + { + "age": "35925284" + }, + { + "x-amz-cf-id": "wXY9DDbUrHJoSYufMPmtErRRutYkp32cOy1b07_NcZFdUScDaLORpw==" + }, + { + "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + }, + { + "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Server" + }, + { + "last-modified": "Wed, 22 Sep 2010 23:59:48 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=613358641" + }, + { + "expires": "Sun, 11 Apr 2032 14:29:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:05:02 GMT" + }, + { + "content-length": "22760" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:05:03 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0M6TJE3FZYTXRNRY512Y" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "uk/tDjh11RBjIvdv0Gj9JUCG/M9iirulGzM8OhRvjW/qch4hPreEf7n4VnzczAr6" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:05:03 GMT" + }, + { + "server": "Server" + }, + { + "x-amz-id-1": "0DNVGFVH4CF96QBN4TM9" + }, + { + "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" + }, + { + "x-amz-id-2": "vE+1ySfLV/mErY5cd7s2NdxUOOOUvbYCVUyYCdjxcxbN3eyQRj3PwWhhDk9+xh+Q" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_22.json b/jetty-http2/http2-hpack/src/test/resources/data/story_22.json new file mode 100644 index 00000000000..a2d70313964 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_22.json @@ -0,0 +1,14947 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:30 GMT" + }, + { + "server": "Apache" + }, + { + "cache-control": "max-age=86400" + }, + { + "expires": "Sun, 04 Nov 2012 12:56:30 GMT" + }, + { + "last-modified": "Tue, 12 Jan 2010 13:48:00 GMT" + }, + { + "etag": "\"51-4b4c7d90\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "81" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/html" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:30 GMT" + }, + { + "server": "Apache" + }, + { + "cache-control": "max-age=86400" + }, + { + "expires": "Sun, 04 Nov 2012 12:56:30 GMT" + }, + { + "last-modified": "Mon, 24 Jan 2011 11:52:00 GMT" + }, + { + "etag": "\"13e-4d3d67e0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "318" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/plain" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:32 GMT" + }, + { + "server": "BWS/1.0" + }, + { + "content-length": "4034" + }, + { + "content-type": "text/html;charset=gbk" + }, + { + "cache-control": "private" + }, + { + "expires": "Sat, 03 Nov 2012 12:56:32 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "set-cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1; expires=Sat, 03-Nov-42 12:56:32 GMT; path=/; domain=.baidu.com" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:32 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 20 Jan 2011 07:15:35 GMT" + }, + { + "etag": "\"65e-49a41e65933c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1630" + }, + { + "cache-control": "max-age=315360000" + }, + { + "expires": "Tue, 01 Nov 2022 12:56:32 GMT" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:32 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 19 Apr 2012 09:51:20 GMT" + }, + { + "etag": "\"5b-4be051d263600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "91" + }, + { + "cache-control": "max-age=315360000" + }, + { + "expires": "Tue, 01 Nov 2022 12:56:32 GMT" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:33 GMT" + }, + { + "server": "Apache" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "set-cookie": "BAIDUID=94A36D239683687B3C92793A22BA0C93:FG=1; expires=Sun, 03-Nov-13 12:56:33 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1" + }, + { + "last-modified": "Thu, 11 Aug 2011 07:44:31 GMT" + }, + { + "etag": "\"57d9-4aa35f79b95c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=315360000" + }, + { + "expires": "Tue, 01 Nov 2022 12:56:33 GMT" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8000" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "application/javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:33 GMT" + }, + { + "server": "Apache" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "set-cookie": "BAIDUID=129ADB92B43CFC527CA7FB93BCB8AB88:FG=1; expires=Sun, 03-Nov-13 12:56:33 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1" + }, + { + "last-modified": "Fri, 02 Nov 2012 06:54:50 GMT" + }, + { + "etag": "\"5555-4cd7d9cac8280\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=315360000" + }, + { + "expires": "Tue, 01 Nov 2022 12:56:33 GMT" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7499" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "application/javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:33 GMT" + }, + { + "server": "Apache" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "set-cookie": "BAIDUID=CC2AAA2AE3AF303A945CAF8E9945BC2D:FG=1; expires=Sun, 03-Nov-13 12:56:33 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1" + }, + { + "last-modified": "Thu, 20 Sep 2012 04:32:55 GMT" + }, + { + "etag": "\"26fa-4ca1a9df6cbc0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=315360000" + }, + { + "expires": "Tue, 01 Nov 2022 12:56:33 GMT" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3586" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "application/javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:33 GMT" + }, + { + "server": "Apache" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "set-cookie": "BAIDUID=6C1D358E43AAD143080C18E498033F71:FG=1; expires=Sun, 03-Nov-13 12:56:33 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1" + }, + { + "last-modified": "Thu, 30 Jun 2011 10:56:51 GMT" + }, + { + "etag": "\"25f-4a6ebc21c42c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "607" + }, + { + "cache-control": "max-age=315360000" + }, + { + "expires": "Tue, 01 Nov 2022 12:56:33 GMT" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/png" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:34 GMT" + }, + { + "server": "Apache" + }, + { + "content-length": "147" + }, + { + "content-type": "image/x-icon" + }, + { + "cache-control": "private" + }, + { + "expires": "Sat, 03 Nov 2012 12:56:32 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "set-cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1; expires=Sat, 03-Nov-42 12:56:32 GMT; path=/; domain=.baidu.com" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "connection": "Keep-Alive" + }, + { + "last-modified": "Mon, 24 Jan 2011 11:52:05 GMT" + }, + { + "etag": "\"13e-49a963a8e0340\"" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding,User-Agent" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "BAIDUID=7B3F07DA7EB7581C6AAAAC2399C0F469:FG=1; max-age=31536000; expires=Sun, 03-Nov-13 12:56:39 GMT; domain=.hao123.com; path=/; version=1" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "expires": "Sat, 03 Nov 2012 12:56:39 GMT" + }, + { + "cache-control": "max-age=0" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 12:56:39 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"2880337125\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 14 Feb 2012 03:23:36 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:40 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "795" + }, + { + "date": "Sat, 03 Nov 2012 12:56:40 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"1970946457\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 21 Aug 2012 12:19:47 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:40 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "49" + }, + { + "date": "Sat, 03 Nov 2012 12:56:40 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"3508231446\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 12 Sep 2012 06:59:30 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:40 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "4465" + }, + { + "date": "Sat, 03 Nov 2012 12:56:40 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:56:41 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "5928" + }, + { + "cache-control": "max-age=31536000" + }, + { + "etag": "\"3116325809147476198\"" + }, + { + "expires": "Sun, 03 Nov 2013 02:09:15 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:07:33 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:56:41 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "10550" + }, + { + "cache-control": "max-age=31536000" + }, + { + "etag": "\"13813589230791420108\"" + }, + { + "expires": "Fri, 01 Nov 2013 10:53:47 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 06:05:04 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/css" + }, + { + "etag": "\"991580451\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 02 Nov 2012 05:07:04 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:40 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11081" + }, + { + "date": "Sat, 03 Nov 2012 12:56:40 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"2826587238\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 18 Sep 2012 06:59:28 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:41 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "1803" + }, + { + "date": "Sat, 03 Nov 2012 12:56:41 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"2820264983\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 18 Sep 2012 02:45:17 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:41 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "3703" + }, + { + "date": "Sat, 03 Nov 2012 12:56:41 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"779014302\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Mon, 06 Aug 2012 10:17:50 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:41 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "2053" + }, + { + "date": "Sat, 03 Nov 2012 12:56:41 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"439052966\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 02 Nov 2012 05:07:03 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:40 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "38609" + }, + { + "date": "Sat, 03 Nov 2012 12:56:40 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"1503293558\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 02 Nov 2012 05:07:03 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:41 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "13174" + }, + { + "date": "Sat, 03 Nov 2012 12:56:41 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"790245820\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 02 Nov 2012 05:07:03 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:40 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "33536" + }, + { + "date": "Sat, 03 Nov 2012 12:56:40 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"1136345403\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 17 Oct 2012 17:08:02 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:43 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "3731" + }, + { + "date": "Sat, 03 Nov 2012 12:56:43 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"1881822353\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 16 Oct 2012 15:28:36 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:43 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1007" + }, + { + "date": "Sat, 03 Nov 2012 12:56:43 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"55301462\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 19 Oct 2012 15:59:17 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:43 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2179" + }, + { + "date": "Sat, 03 Nov 2012 12:56:43 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "BAIDUID=7B3F07DA7EB7581C6AAAAC2399C0F469:FG=1; max-age=31536000; expires=Sun, 03-Nov-13 12:56:39 GMT; domain=.hao123.com; path=/; version=1" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:43 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 12:56:43 GMT" + }, + { + "server": "BWS/1.0" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"2082195828\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 18 Jan 2011 06:39:02 GMT" + }, + { + "content-length": "43" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"2082195828\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 18 Jan 2011 06:39:02 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:43 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 12:56:43 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"1129043035\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 19 Oct 2012 15:58:50 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:43 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1962" + }, + { + "date": "Sat, 03 Nov 2012 12:56:43 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:56:43 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "1076" + }, + { + "etag": "\"2330871933\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 13 Jul 2012 03:17:42 GMT" + }, + { + "expires": "Sat, 12 Jan 2013 11:31:05 GMT" + }, + { + "cache-control": "max-age=15552000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"2084456863\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 18 Jan 2011 03:02:19 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:43 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 12:56:43 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:44 GMT" + }, + { + "server": "ECOM Apache 1.0.13.0" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/html" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"1905870111\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 18 Nov 2009 09:44:09 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 12:56:44 GMT" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 12:56:44 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.15" + }, + { + "date": "Sat, 03 Nov 2012 12:57:18 GMT" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "No-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "set-cookie": "JSESSIONID=24206446514B3C020AC50919B9330503; Path=/" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "x-powered-by": "PHP/5.2.3" + }, + { + "cache-control": "max-age=259200" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Tue, 06 Nov 2012 12:56:46 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "set-cookie": "loc=1%7C%B1%B1%BE%A9%7C%B1%B1%BE%A9; expires=Tue, 06-Nov-2012 12:56:46 GMT; path=/; domain=.hao123.com" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "684" + }, + { + "date": "Sat, 03 Nov 2012 12:56:46 GMT" + }, + { + "server": "lighttpd" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "media": "media" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Fri, 26 Oct 2012 12:24:13 GMT" + }, + { + "last-modified": "Sat, 25 Apr 2009 07:04:00 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 12:56:46 GMT" + }, + { + "server": "apache" + }, + { + "content-length": "8992" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.0" + }, + { + "date": "Sat, 03 Nov 2012 12:56:47 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Thu, 01 Nov 2012 10:00:20 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "expires": "Sat, 03 Nov 2012 13:26:47 GMT" + }, + { + "cache-control": "max-age=1800" + }, + { + "set-cookie": "id58=05eNElCVFI9c8Hfk16UMAg==; expires=Tue, 01-Nov-22 12:56:47 GMT; domain=58.com; path=/" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"CUR ADM OUR NOR STA NID\"" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"1840151033\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 14 Feb 2012 03:23:36 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:47 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4959" + }, + { + "date": "Sat, 03 Nov 2012 12:56:47 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"1236171233\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 14 Feb 2012 03:23:36 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:47 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4571" + }, + { + "date": "Sat, 03 Nov 2012 12:56:47 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "BAIDUID=7B3F07DA7EB7581C6AAAAC2399C0F469:FG=1; max-age=31536000; expires=Sun, 03-Nov-13 12:56:39 GMT; domain=.hao123.com; path=/; version=1" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "expires": "Tue, 29 Oct 2013 12:56:47 GMT" + }, + { + "cache-control": "max-age=31104000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 12:56:47 GMT" + }, + { + "server": "BWS/1.0" + }, + { + "content-type": "image/x-icon" + }, + { + "etag": "\"567172269\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 01 Mar 2012 02:31:58 GMT" + }, + { + "content-length": "1150" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:54:27 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "last-modified": "Thu, 16 Aug 2012 08:37:54 GMT" + }, + { + "cache-control": "max-age=300" + }, + { + "content-encoding": "gzip" + }, + { + "age": "1" + }, + { + "x-via": "1.1 bjgm232:8102 (Cdn Cache Server V2.0), 1.1 stsz70:8105 (Cdn Cache Server V2.0), 1.1 gdyf13:9080 (Cdn Cache Server V2.0)" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Mon, 22 Oct 2012 04:02:33 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "22332" + }, + { + "last-modified": "Mon, 25 Apr 2011 10:41:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "1" + }, + { + "x-via": "1.1 gm240:8104 (Cdn Cache Server V2.0), 1.1 stcz163:8106 (Cdn Cache Server V2.0), 1.1 gdyf13:8184 (Cdn Cache Server V2.0)" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Fri, 26 Oct 2012 12:49:31 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "9309" + }, + { + "last-modified": "Mon, 25 Apr 2011 08:07:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "1" + }, + { + "x-via": "1.1 gm243:8106 (Cdn Cache Server V2.0), 1.1 stsz75:8104 (Cdn Cache Server V2.0), 1.1 gdyf16:9080 (Cdn Cache Server V2.0)" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.2.0" + }, + { + "date": "Sat, 03 Nov 2012 12:56:49 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 16 Aug 2012 08:37:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Fri, 26 Oct 2012 12:49:31 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "23163" + }, + { + "last-modified": "Mon, 25 Apr 2011 10:46:11 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "1" + }, + { + "x-via": "1.1 gm240:8101 (Cdn Cache Server V2.0), 1.1 stsz74:8080 (Cdn Cache Server V2.0), 1.1 gdyf17:8184 (Cdn Cache Server V2.0)" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Fri, 26 Oct 2012 12:49:21 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "281" + }, + { + "last-modified": "Mon, 25 Apr 2011 08:07:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "1" + }, + { + "x-via": "1.1 gm239:8102 (Cdn Cache Server V2.0), 1.1 stsz70:88 (Cdn Cache Server V2.0), 1.1 gdyf20:8184 (Cdn Cache Server V2.0)" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Thu, 01 Nov 2012 04:29:06 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "183" + }, + { + "last-modified": "Wed, 11 Jan 2012 07:50:38 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "1" + }, + { + "x-via": "1.1 tjtg100:80 (Cdn Cache Server V2.0), 1.1 gm240:8106 (Cdn Cache Server V2.0), 1.1 stsz75:8107 (Cdn Cache Server V2.0), 1.1 gdyf18:8360 (Cdn Cache Server V2.0)" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.0" + }, + { + "date": "Sat, 03 Nov 2012 12:56:50 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Sun, 24 Apr 2011 02:10:42 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "expires": "Sat, 03 Nov 2012 13:26:50 GMT" + }, + { + "cache-control": "max-age=1800" + }, + { + "set-cookie": "id58=05eNElCVFI9c8Hfk16UMAg==; expires=Tue, 01-Nov-22 12:56:47 GMT; domain=58.com; path=/" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"CUR ADM OUR NOR STA NID\"" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "35" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.2.3" + }, + { + "date": "Sat, 03 Nov 2012 12:56:50 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "35" + }, + { + "last-modified": "Tue, 16 Oct 2012 03:32:08 GMT" + }, + { + "connection": "keep-alive" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Thu, 18 Oct 2012 03:17:25 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "11545" + }, + { + "last-modified": "Mon, 25 Apr 2011 09:08:36 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "1" + }, + { + "x-via": "1.1 gm240:8107 (Cdn Cache Server V2.0), 1.1 stcz158:8104 (Cdn Cache Server V2.0), 1.1 gdyf16:8184 (Cdn Cache Server V2.0)" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 12:56:51 GMT" + }, + { + "content-type": "text/html" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com" + }, + { + "location": "http://tieba.baidu.com/index.html" + }, + { + "tracecode": "34115693691177833738110320" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.15" + }, + { + "date": "Sat, 03 Nov 2012 12:57:24 GMT" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "No-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "set-cookie": "JSESSIONID=24206446514B3C020AC50919B9330503; Path=/" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "W/\"4286-1337327987000\"" + }, + { + "last-modified": "Fri, 18 May 2012 07:59:47 GMT" + }, + { + "content-length": "4286" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "5352" + }, + { + "cache-control": "max-age=31536000" + }, + { + "etag": "\"3854054371452794933\"" + }, + { + "expires": "Fri, 01 Nov 2013 07:42:36 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 07:18:44 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "20557" + }, + { + "last-modified": "Fri, 02 Nov 2012 01:59:00 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"1496242645\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Sun, 15 Aug 2010 16:00:00 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:56:52 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "content-length": "1574" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "13644" + }, + { + "last-modified": "Sat, 03 Nov 2012 03:33:51 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "8122" + }, + { + "last-modified": "Wed, 31 Oct 2012 06:49:50 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:51 GMT" + }, + { + "content-type": "text/html" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 11:28:20 GMT" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "19956" + }, + { + "last-modified": "Sat, 03 Nov 2012 06:36:26 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 07:23:32 GMT" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4240" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"464442779\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Sun, 15 Aug 2010 16:00:00 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:56:53 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "content-length": "231" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"531551641\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Sun, 15 Aug 2010 16:00:00 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:56:53 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "content-length": "339" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "server": "ECOM Apache 1.0.13.0" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/html" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "7748" + }, + { + "last-modified": "Fri, 02 Nov 2012 03:02:59 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com" + }, + { + "location": "http://tieba.baidu.com/index.html" + }, + { + "tracecode": "34115693691177833738110320" + }, + { + "server": "Apache" + }, + { + "content-length": "29476" + }, + { + "last-modified": "Sat, 03 Nov 2012 03:31:40 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 05:21:05 GMT" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7301" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "7993" + }, + { + "last-modified": "Thu, 01 Nov 2012 07:14:19 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "last-modified": "Thu, 14 Oct 2010 10:10:45 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 29 Oct 2010 06:30:56 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:13:02 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "35637" + }, + { + "last-modified": "Wed, 31 Oct 2012 04:22:40 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com" + }, + { + "location": "http://tieba.baidu.com/index.html" + }, + { + "tracecode": "34115693691177833738110320" + }, + { + "server": "Apache" + }, + { + "content-length": "4997" + }, + { + "last-modified": "Thu, 21 Jun 2012 03:57:37 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 29 Jun 2012 10:13:16 GMT" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2267" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "1480" + }, + { + "last-modified": "Mon, 21 May 2012 07:58:06 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "8922" + }, + { + "last-modified": "Mon, 22 Oct 2012 03:21:07 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "etag": "\"4172175030\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 23 Oct 2012 10:48:27 GMT" + }, + { + "content-length": "9393" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "server": "apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "9294" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:16:26 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "40299" + }, + { + "last-modified": "Fri, 02 Nov 2012 04:07:00 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:52 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8579" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "18605" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com" + }, + { + "location": "http://tieba.baidu.com/index.html" + }, + { + "tracecode": "34115693691177833738110320" + }, + { + "server": "Apache" + }, + { + "content-length": "20099" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "18865" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "20123" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "server": "Apache" + }, + { + "location": "http://msg.baidu.com/msg/msg_dataGetmsgCount?from=msg" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "206" + }, + { + "connection": "close" + }, + { + "content-type": "text/html; charset=iso-8859-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "17869" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "18072" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "21328" + }, + { + "last-modified": "Wed, 19 Jan 2011 09:16:11 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/gif" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "1481" + }, + { + "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "220" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "etag": "\"3965408141\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 16 Oct 2012 06:54:58 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:56:52 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "content-length": "39993" + }, + { + "date": "Sat, 03 Nov 2012 12:56:52 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "11279" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "22384" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com" + }, + { + "location": "http://tieba.baidu.com/index.html" + }, + { + "tracecode": "34115693691177833738110320" + }, + { + "server": "Apache" + }, + { + "content-length": "20962" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "61444" + }, + { + "last-modified": "Wed, 31 Oct 2012 07:13:16 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:54 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "17732" + }, + { + "last-modified": "Fri, 02 Nov 2012 09:16:23 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 26 Oct 2012 12:58:13 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:53 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:53 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 11 Oct 2011 07:38:09 GMT" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "999" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "3949" + }, + { + "last-modified": "Mon, 27 Aug 2012 06:36:50 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "1158" + }, + { + "last-modified": "Mon, 03 Sep 2012 03:47:57 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "1008" + }, + { + "last-modified": "Mon, 27 Aug 2012 08:26:17 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3059" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "text/html; charset=GBK" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "Keep-Alive" + }, + { + "set-cookie": "TIEBA_USERTYPE=7a2a671a262b15b7e6f4819b; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com" + }, + { + "location": "http://tieba.baidu.com/index.html" + }, + { + "tracecode": "34173872330388372234110320" + }, + { + "server": "Apache" + }, + { + "content-length": "20962" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:54 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "text/html; charset=GBK" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "1158" + }, + { + "last-modified": "Mon, 03 Sep 2012 03:47:57 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "tracecode": "34176809970478157322110320" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "607" + }, + { + "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2921" + }, + { + "last-modified": "Tue, 17 May 2011 06:39:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2832" + }, + { + "last-modified": "Tue, 17 May 2011 06:39:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "3059" + }, + { + "last-modified": "Tue, 17 May 2011 06:39:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2801" + }, + { + "last-modified": "Tue, 17 May 2011 06:39:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2923" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "20220" + }, + { + "last-modified": "Tue, 30 Oct 2012 07:56:05 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2830" + }, + { + "last-modified": "Tue, 17 May 2011 06:39:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:58 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2877" + }, + { + "last-modified": "Tue, 17 May 2011 06:39:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:58 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2967" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:58 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "177" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:58 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "content-type": "text/html; charset=GBK" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "1158" + }, + { + "last-modified": "Mon, 03 Sep 2012 03:47:57 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:57 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "tracecode": "34180192590438703882110320" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "7067" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:58 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:12:51 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:58 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "288" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "8236" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:58 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2842" + }, + { + "last-modified": "Tue, 17 May 2011 06:39:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:59 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"4291424757\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 21 Jun 2012 08:04:46 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:56:59 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3558" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/html" + }, + { + "etag": "\"4232694198\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 21 Jun 2012 08:04:45 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:56:59 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10901" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=44849399" + }, + { + "expires": "Sun, 06 Apr 2014 15:06:58 GMT" + }, + { + "last-modified": "Thu, 31 Dec 2009 08:37:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=40280084" + }, + { + "expires": "Wed, 12 Feb 2014 17:51:43 GMT" + }, + { + "last-modified": "Fri, 16 Apr 2010 03:07:31 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12713623" + }, + { + "expires": "Sat, 30 Mar 2013 16:30:42 GMT" + }, + { + "last-modified": "Sat, 14 Jan 2012 05:49:33 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=33539862" + }, + { + "expires": "Tue, 26 Nov 2013 17:34:41 GMT" + }, + { + "last-modified": "Sun, 19 Sep 2010 03:41:35 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4405195" + }, + { + "expires": "Mon, 24 Dec 2012 12:36:54 GMT" + }, + { + "last-modified": "Tue, 24 Jul 2012 13:37:09 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "media": "media" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Fri, 26 Oct 2012 12:24:13 GMT" + }, + { + "last-modified": "Sat, 25 Apr 2009 07:04:00 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 12:56:58 GMT" + }, + { + "server": "apache" + }, + { + "content-length": "27159" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"2269828500\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 24 Aug 2010 14:26:41 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:56:59 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "571" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=25111771" + }, + { + "expires": "Wed, 21 Aug 2013 04:26:30 GMT" + }, + { + "last-modified": "Sat, 02 Apr 2011 05:57:56 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=9297121" + }, + { + "expires": "Tue, 19 Feb 2013 03:29:00 GMT" + }, + { + "last-modified": "Mon, 02 Apr 2012 07:52:56 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=41820075" + }, + { + "expires": "Sun, 02 Mar 2014 13:38:14 GMT" + }, + { + "last-modified": "Thu, 11 Mar 2010 11:34:29 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=10209204" + }, + { + "expires": "Fri, 01 Mar 2013 16:50:23 GMT" + }, + { + "last-modified": "Mon, 12 Mar 2012 05:10:10 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "etag": "eab7a0d6b87c3b4ed2c270c0380dbf29" + }, + { + "cache-control": "max-age=0, must-revalidate" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "application/javascript" + }, + { + "set-cookie": "HMACCOUNT=0F8500D919421ADB; Path=/; Domain=hm.baidu.com; Expires=Sun, 18 Jan 2038 00:00:00 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "connection": "close" + }, + { + "content-length": "5779" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=8515483" + }, + { + "expires": "Sun, 10 Feb 2013 02:21:42 GMT" + }, + { + "last-modified": "Fri, 20 Apr 2012 10:07:32 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, max-age=0, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "x-content-type-options": "nosniff" + }, + { + "connection": "close" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 12:57:00 GMT" + }, + { + "server": "apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:00 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "1158" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:54:28 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:00 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "tracecode": "34180192590438703882110320" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:00 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "1158" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:54:28 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:00 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "tracecode": "34180192590438703882110320" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:00 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "3949" + }, + { + "last-modified": "Fri, 02 Nov 2012 12:11:36 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:00 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "BAIDUID=53B0A4069A29BECD16EF519984CCA005:FG=1; max-age=946080000; expires=Mon, 27-Oct-42 12:57:02 GMT; domain=.baidu.com; path=/; version=1" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"1698673572\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:49:58 GMT" + }, + { + "expires": "Fri, 01 Feb 2013 12:57:02 GMT" + }, + { + "cache-control": "max-age=7776000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "502" + }, + { + "date": "Sat, 03 Nov 2012 12:57:02 GMT" + }, + { + "server": "apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "BAIDUID=53B0A4069A29BECDD09DC829CEEA31EE:FG=1; max-age=946080000; expires=Mon, 27-Oct-42 12:57:02 GMT; domain=.baidu.com; path=/; version=1" + }, + { + "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \"" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"2769205800\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:49:58 GMT" + }, + { + "expires": "Fri, 01 Feb 2013 12:57:02 GMT" + }, + { + "cache-control": "max-age=7776000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3712" + }, + { + "date": "Sat, 03 Nov 2012 12:57:02 GMT" + }, + { + "server": "apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"1610142698\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 21 Jun 2012 08:04:47 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:56:59 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "158920" + }, + { + "date": "Sat, 03 Nov 2012 12:56:59 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:04 GMT" + }, + { + "content-type": "image/x-icon" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "2550" + }, + { + "last-modified": "Tue, 30 Mar 2010 09:25:50 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:04 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "tracecode": "34180192590438703882110320" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:07 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:11:42 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:56:58 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "43" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"1905870111\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 18 Nov 2009 09:44:09 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 12:57:07 GMT" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 12:57:07 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, max-age=0, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "x-content-type-options": "nosniff" + }, + { + "connection": "close" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 12:57:07 GMT" + }, + { + "server": "apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Tue, 30 Oct 2012 09:21:56 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "787" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "522" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/x-icon" + }, + { + "content-length": "2550" + }, + { + "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=14920916" + }, + { + "expires": "Thu, 25 Apr 2013 05:39:04 GMT" + }, + { + "last-modified": "Thu, 24 Nov 2011 03:33:15 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=20272763" + }, + { + "expires": "Wed, 26 Jun 2013 04:16:31 GMT" + }, + { + "last-modified": "Sat, 23 Jul 2011 06:18:22 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3386843" + }, + { + "expires": "Wed, 12 Dec 2012 17:44:31 GMT" + }, + { + "last-modified": "Fri, 17 Aug 2012 03:22:22 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=319801" + }, + { + "expires": "Wed, 07 Nov 2012 05:47:09 GMT" + }, + { + "last-modified": "Sat, 27 Oct 2012 03:17:06 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "etag": "\"2813066485\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 12 Aug 2010 08:49:52 GMT" + }, + { + "expires": "Mon, 12 Sep 2022 12:57:08 GMT" + }, + { + "cache-control": "max-age=311040000" + }, + { + "content-length": "1490" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4715" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5848" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Thu, 29 Mar 2012 08:20:20 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1173183" + }, + { + "expires": "Sat, 17 Nov 2012 02:50:11 GMT" + }, + { + "last-modified": "Sun, 07 Oct 2012 09:11:02 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=131604" + }, + { + "expires": "Mon, 05 Nov 2012 01:30:32 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 11:50:19 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=305486" + }, + { + "expires": "Wed, 07 Nov 2012 01:48:34 GMT" + }, + { + "last-modified": "Sat, 27 Oct 2012 11:14:16 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=10106809" + }, + { + "expires": "Thu, 28 Feb 2013 12:23:57 GMT" + }, + { + "last-modified": "Wed, 14 Mar 2012 14:03:29 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=11660411" + }, + { + "expires": "Mon, 18 Mar 2013 11:57:19 GMT" + }, + { + "last-modified": "Tue, 07 Feb 2012 14:56:45 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1356978" + }, + { + "expires": "Mon, 19 Nov 2012 05:53:26 GMT" + }, + { + "last-modified": "Wed, 03 Oct 2012 03:04:31 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=10204165" + }, + { + "expires": "Fri, 01 Mar 2013 15:26:33 GMT" + }, + { + "last-modified": "Mon, 12 Mar 2012 07:58:17 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=9726906" + }, + { + "expires": "Sun, 24 Feb 2013 02:52:14 GMT" + }, + { + "last-modified": "Fri, 23 Mar 2012 09:06:55 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2265452" + }, + { + "expires": "Thu, 29 Nov 2012 18:14:40 GMT" + }, + { + "last-modified": "Wed, 12 Sep 2012 02:22:04 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "8761" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5828" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "6430" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6892" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "4639" + }, + { + "last-modified": "Fri, 02 Nov 2012 10:10:35 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "853" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=6834284" + }, + { + "expires": "Mon, 21 Jan 2013 15:21:52 GMT" + }, + { + "last-modified": "Tue, 29 May 2012 08:07:39 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=8117075" + }, + { + "expires": "Tue, 05 Feb 2013 11:41:43 GMT" + }, + { + "last-modified": "Sun, 29 Apr 2012 15:27:57 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=6108255" + }, + { + "expires": "Sun, 13 Jan 2013 05:41:23 GMT" + }, + { + "last-modified": "Fri, 15 Jun 2012 03:28:38 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2157496" + }, + { + "expires": "Wed, 28 Nov 2012 12:15:24 GMT" + }, + { + "last-modified": "Fri, 14 Sep 2012 14:20:35 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=7406109" + }, + { + "expires": "Mon, 28 Jan 2013 06:12:17 GMT" + }, + { + "last-modified": "Wed, 16 May 2012 02:26:49 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5979956" + }, + { + "expires": "Fri, 11 Jan 2013 18:03:04 GMT" + }, + { + "last-modified": "Mon, 18 Jun 2012 02:45:15 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12913110" + }, + { + "expires": "Mon, 01 Apr 2013 23:55:38 GMT" + }, + { + "last-modified": "Mon, 09 Jan 2012 15:00:07 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "4639" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:08 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3673" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "834" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Fri, 02 Nov 2012 10:10:35 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5828" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "586" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "581" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5746593" + }, + { + "expires": "Wed, 09 Jan 2013 01:13:42 GMT" + }, + { + "last-modified": "Sat, 23 Jun 2012 12:24:03 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4420208" + }, + { + "expires": "Mon, 24 Dec 2012 16:47:17 GMT" + }, + { + "last-modified": "Tue, 24 Jul 2012 05:16:52 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "text/html; charset=GBK" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "2550" + }, + { + "last-modified": "Tue, 30 Mar 2010 09:25:50 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:04 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "tracecode": "34277428450405149450110320" + }, + { + "content-encoding": "gzip" + }, + { + "set-cookie": "wise_device=0; expires=Sun, 03-Nov-2013 12:57:07 GMT; path=/" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=750933" + }, + { + "expires": "Mon, 12 Nov 2012 05:32:42 GMT" + }, + { + "last-modified": "Wed, 17 Oct 2012 03:46:02 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=31704989" + }, + { + "expires": "Tue, 05 Nov 2013 11:53:37 GMT" + }, + { + "last-modified": "Sun, 31 Oct 2010 15:04:09 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2436757" + }, + { + "expires": "Sat, 01 Dec 2012 17:49:46 GMT" + }, + { + "last-modified": "Sat, 08 Sep 2012 03:11:54 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=108530" + }, + { + "expires": "Sun, 04 Nov 2012 19:05:59 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 00:39:29 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=519223" + }, + { + "expires": "Fri, 09 Nov 2012 13:10:52 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 12:29:43 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3860382" + }, + { + "expires": "Tue, 18 Dec 2012 05:16:51 GMT" + }, + { + "last-modified": "Mon, 06 Aug 2012 04:17:45 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Tue, 30 Oct 2012 09:21:56 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "2820" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "618" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "572" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=9498052" + }, + { + "expires": "Thu, 21 Feb 2013 11:18:01 GMT" + }, + { + "last-modified": "Wed, 28 Mar 2012 16:15:24 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4541952" + }, + { + "expires": "Wed, 26 Dec 2012 02:36:21 GMT" + }, + { + "last-modified": "Sat, 21 Jul 2012 09:38:45 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4854455" + }, + { + "expires": "Sat, 29 Dec 2012 17:24:44 GMT" + }, + { + "last-modified": "Sat, 14 Jul 2012 04:01:58 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=217395" + }, + { + "expires": "Tue, 06 Nov 2012 01:20:24 GMT" + }, + { + "last-modified": "Mon, 29 Oct 2012 12:10:39 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=606214" + }, + { + "expires": "Sat, 10 Nov 2012 13:20:43 GMT" + }, + { + "last-modified": "Sat, 20 Oct 2012 12:10:00 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=10024120" + }, + { + "expires": "Wed, 27 Feb 2013 13:25:49 GMT" + }, + { + "last-modified": "Fri, 16 Mar 2012 11:59:49 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4573190" + }, + { + "expires": "Wed, 26 Dec 2012 11:16:59 GMT" + }, + { + "last-modified": "Fri, 20 Jul 2012 16:17:28 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=8773628" + }, + { + "expires": "Wed, 13 Feb 2013 02:04:17 GMT" + }, + { + "last-modified": "Sat, 14 Apr 2012 10:42:52 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "10566" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "840" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "10010" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "5929" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1970" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2878" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2367" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "138" + }, + { + "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "248" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "340" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "522" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1284" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "142" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2867849" + }, + { + "expires": "Thu, 06 Dec 2012 17:34:38 GMT" + }, + { + "last-modified": "Wed, 29 Aug 2012 03:42:11 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=742724" + }, + { + "expires": "Mon, 12 Nov 2012 03:15:53 GMT" + }, + { + "last-modified": "Wed, 17 Oct 2012 08:19:41 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1777991" + }, + { + "expires": "Sat, 24 Nov 2012 02:50:20 GMT" + }, + { + "last-modified": "Sun, 23 Sep 2012 09:10:47 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=962398" + }, + { + "expires": "Wed, 14 Nov 2012 16:17:07 GMT" + }, + { + "last-modified": "Fri, 12 Oct 2012 06:17:12 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=14125794" + }, + { + "expires": "Tue, 16 Apr 2013 00:47:03 GMT" + }, + { + "last-modified": "Mon, 12 Dec 2011 13:17:20 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "954" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=431506" + }, + { + "expires": "Thu, 08 Nov 2012 12:48:55 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 13:13:37 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=11487816" + }, + { + "expires": "Sat, 16 Mar 2013 12:00:45 GMT" + }, + { + "last-modified": "Sat, 11 Feb 2012 14:49:57 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2738958" + }, + { + "expires": "Wed, 05 Dec 2012 05:46:27 GMT" + }, + { + "last-modified": "Sat, 01 Sep 2012 03:18:32 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5566505" + }, + { + "expires": "Sun, 06 Jan 2013 23:12:14 GMT" + }, + { + "last-modified": "Wed, 27 Jun 2012 16:26:59 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "3063" + }, + { + "last-modified": "Fri, 02 Nov 2012 10:10:36 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "539" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "17226" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "833" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "820" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:10 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:12:46 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4911" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1394" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:10 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "5772" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10954" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "994" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:10 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=54046405" + }, + { + "expires": "Tue, 22 Jul 2014 01:50:34 GMT" + }, + { + "last-modified": "Mon, 01 Jun 2009 11:10:18 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=707871" + }, + { + "expires": "Sun, 11 Nov 2012 17:35:01 GMT" + }, + { + "last-modified": "Thu, 18 Oct 2012 03:41:27 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=362012" + }, + { + "expires": "Wed, 07 Nov 2012 17:30:42 GMT" + }, + { + "last-modified": "Fri, 26 Oct 2012 03:50:06 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=18793623" + }, + { + "expires": "Sun, 09 Jun 2013 01:24:13 GMT" + }, + { + "last-modified": "Fri, 26 Aug 2011 12:03:04 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=430516" + }, + { + "expires": "Thu, 08 Nov 2012 12:32:26 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 13:46:37 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=32880607" + }, + { + "expires": "Tue, 19 Nov 2013 02:27:17 GMT" + }, + { + "last-modified": "Mon, 04 Oct 2010 09:56:55 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3367264" + }, + { + "expires": "Wed, 12 Dec 2012 12:18:14 GMT" + }, + { + "last-modified": "Fri, 17 Aug 2012 14:15:02 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3543896" + }, + { + "expires": "Fri, 14 Dec 2012 13:22:06 GMT" + }, + { + "last-modified": "Mon, 13 Aug 2012 12:07:18 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "2725" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:10 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:54:28 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "4823" + }, + { + "last-modified": "Wed, 14 Sep 2011 06:12:46 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:10 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "598" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "4344" + }, + { + "last-modified": "Fri, 09 Sep 2011 07:29:20 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:10 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=920631" + }, + { + "expires": "Wed, 14 Nov 2012 04:41:01 GMT" + }, + { + "last-modified": "Sat, 13 Oct 2012 05:29:27 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=10801080" + }, + { + "expires": "Fri, 08 Mar 2013 13:15:10 GMT" + }, + { + "last-modified": "Mon, 27 Feb 2012 12:21:10 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=19349568" + }, + { + "expires": "Sat, 15 Jun 2013 11:49:58 GMT" + }, + { + "last-modified": "Sat, 13 Aug 2011 15:11:34 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2597506" + }, + { + "expires": "Mon, 03 Dec 2012 14:28:56 GMT" + }, + { + "last-modified": "Tue, 04 Sep 2012 09:53:37 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=27218873" + }, + { + "expires": "Sat, 14 Sep 2013 13:45:03 GMT" + }, + { + "last-modified": "Sat, 12 Feb 2011 11:21:23 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3377775" + }, + { + "expires": "Wed, 12 Dec 2012 15:13:25 GMT" + }, + { + "last-modified": "Fri, 17 Aug 2012 08:24:39 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4247008" + }, + { + "expires": "Sat, 22 Dec 2012 16:40:38 GMT" + }, + { + "last-modified": "Sat, 28 Jul 2012 05:30:14 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1815543" + }, + { + "expires": "Sat, 24 Nov 2012 13:16:13 GMT" + }, + { + "last-modified": "Sat, 22 Sep 2012 12:19:04 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=270710" + }, + { + "expires": "Tue, 06 Nov 2012 16:09:00 GMT" + }, + { + "last-modified": "Sun, 28 Oct 2012 06:33:30 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1790915" + }, + { + "expires": "Sat, 24 Nov 2012 06:25:45 GMT" + }, + { + "last-modified": "Sun, 23 Sep 2012 02:00:00 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=14218" + }, + { + "expires": "Sat, 03 Nov 2012 16:54:08 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:03:14 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3723118" + }, + { + "expires": "Sun, 16 Dec 2012 15:09:08 GMT" + }, + { + "last-modified": "Thu, 09 Aug 2012 08:33:13 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4635533" + }, + { + "expires": "Thu, 27 Dec 2012 04:36:03 GMT" + }, + { + "last-modified": "Thu, 19 Jul 2012 05:39:24 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12138710" + }, + { + "expires": "Sun, 24 Mar 2013 00:49:00 GMT" + }, + { + "last-modified": "Fri, 27 Jan 2012 13:13:30 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=19371229" + }, + { + "expires": "Sat, 15 Jun 2013 17:50:59 GMT" + }, + { + "last-modified": "Sat, 13 Aug 2011 03:09:31 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3202347" + }, + { + "expires": "Mon, 10 Dec 2012 14:29:37 GMT" + }, + { + "last-modified": "Tue, 21 Aug 2012 09:52:15 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3678437" + }, + { + "expires": "Sun, 16 Dec 2012 02:44:27 GMT" + }, + { + "last-modified": "Fri, 10 Aug 2012 09:22:36 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1085523" + }, + { + "expires": "Fri, 16 Nov 2012 02:29:13 GMT" + }, + { + "last-modified": "Tue, 09 Oct 2012 09:53:04 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=51122420" + }, + { + "expires": "Wed, 18 Jun 2014 05:37:30 GMT" + }, + { + "last-modified": "Sat, 08 Aug 2009 03:36:30 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4381984" + }, + { + "expires": "Mon, 24 Dec 2012 06:10:14 GMT" + }, + { + "last-modified": "Wed, 25 Jul 2012 02:31:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=7305155" + }, + { + "expires": "Sun, 27 Jan 2013 02:09:45 GMT" + }, + { + "last-modified": "Fri, 18 May 2012 10:32:00 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=13340027" + }, + { + "expires": "Sat, 06 Apr 2013 22:30:57 GMT" + }, + { + "last-modified": "Fri, 30 Dec 2011 17:49:36 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3517984" + }, + { + "expires": "Fri, 14 Dec 2012 06:10:14 GMT" + }, + { + "last-modified": "Tue, 14 Aug 2012 02:31:02 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4872542" + }, + { + "expires": "Sat, 29 Dec 2012 22:26:12 GMT" + }, + { + "last-modified": "Fri, 13 Jul 2012 17:59:05 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "48731" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1855967" + }, + { + "expires": "Sun, 25 Nov 2012 00:29:57 GMT" + }, + { + "last-modified": "Fri, 21 Sep 2012 13:51:36 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1357261" + }, + { + "expires": "Mon, 19 Nov 2012 05:58:11 GMT" + }, + { + "last-modified": "Wed, 03 Oct 2012 02:55:08 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12271010" + }, + { + "expires": "Mon, 25 Mar 2013 13:34:00 GMT" + }, + { + "last-modified": "Tue, 24 Jan 2012 11:43:29 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1069555" + }, + { + "expires": "Thu, 15 Nov 2012 22:03:05 GMT" + }, + { + "last-modified": "Tue, 09 Oct 2012 18:45:20 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3114138" + }, + { + "expires": "Sun, 09 Dec 2012 13:59:29 GMT" + }, + { + "last-modified": "Thu, 23 Aug 2012 10:52:35 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=15254111" + }, + { + "expires": "Mon, 29 Apr 2013 02:12:22 GMT" + }, + { + "last-modified": "Wed, 16 Nov 2011 10:26:48 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:10 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "6834" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:10 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1956253" + }, + { + "expires": "Mon, 26 Nov 2012 04:21:24 GMT" + }, + { + "last-modified": "Wed, 19 Sep 2012 06:08:44 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3164696" + }, + { + "expires": "Mon, 10 Dec 2012 04:02:07 GMT" + }, + { + "last-modified": "Wed, 22 Aug 2012 06:47:19 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=15466892" + }, + { + "expires": "Wed, 01 May 2013 13:18:43 GMT" + }, + { + "last-modified": "Fri, 11 Nov 2011 12:14:06 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=56032" + }, + { + "expires": "Sun, 04 Nov 2012 04:31:03 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 05:49:26 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=7623169" + }, + { + "expires": "Wed, 30 Jan 2013 18:30:00 GMT" + }, + { + "last-modified": "Fri, 11 May 2012 01:51:32 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12924665" + }, + { + "expires": "Tue, 02 Apr 2013 03:08:16 GMT" + }, + { + "last-modified": "Mon, 09 Jan 2012 08:35:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2176101" + }, + { + "expires": "Wed, 28 Nov 2012 17:25:32 GMT" + }, + { + "last-modified": "Fri, 14 Sep 2012 04:00:28 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=14007174" + }, + { + "expires": "Sun, 14 Apr 2013 15:50:05 GMT" + }, + { + "last-modified": "Thu, 15 Dec 2011 07:11:23 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1438855" + }, + { + "expires": "Tue, 20 Nov 2012 04:38:06 GMT" + }, + { + "last-modified": "Mon, 01 Oct 2012 05:35:21 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=6323658" + }, + { + "expires": "Tue, 15 Jan 2013 17:31:29 GMT" + }, + { + "last-modified": "Sun, 10 Jun 2012 03:48:34 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=41611" + }, + { + "expires": "Sun, 04 Nov 2012 00:30:42 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:50:08 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=25072164" + }, + { + "expires": "Tue, 20 Aug 2013 17:26:35 GMT" + }, + { + "last-modified": "Sun, 03 Apr 2011 03:58:23 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=13004317" + }, + { + "expires": "Wed, 03 Apr 2013 01:15:48 GMT" + }, + { + "last-modified": "Sat, 07 Jan 2012 12:19:57 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=778015" + }, + { + "expires": "Mon, 12 Nov 2012 13:04:06 GMT" + }, + { + "last-modified": "Tue, 16 Oct 2012 12:43:21 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1778334" + }, + { + "expires": "Sat, 24 Nov 2012 02:56:05 GMT" + }, + { + "last-modified": "Sun, 23 Sep 2012 08:59:23 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5531525" + }, + { + "expires": "Sun, 06 Jan 2013 13:29:16 GMT" + }, + { + "last-modified": "Thu, 28 Jun 2012 11:53:00 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2468675" + }, + { + "expires": "Sun, 02 Dec 2012 02:41:46 GMT" + }, + { + "last-modified": "Fri, 07 Sep 2012 09:28:00 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1223853" + }, + { + "expires": "Sat, 17 Nov 2012 16:54:44 GMT" + }, + { + "last-modified": "Sat, 06 Oct 2012 05:02:04 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3496295" + }, + { + "expires": "Fri, 14 Dec 2012 00:08:46 GMT" + }, + { + "last-modified": "Tue, 14 Aug 2012 14:34:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:09 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:09 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=20150086" + }, + { + "expires": "Mon, 24 Jun 2013 18:11:57 GMT" + }, + { + "last-modified": "Tue, 26 Jul 2011 02:27:39 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:11 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5057999" + }, + { + "expires": "Tue, 01 Jan 2013 01:57:10 GMT" + }, + { + "last-modified": "Mon, 09 Jul 2012 10:57:13 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2613405" + }, + { + "expires": "Mon, 03 Dec 2012 18:53:57 GMT" + }, + { + "last-modified": "Tue, 04 Sep 2012 01:03:41 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4365433" + }, + { + "expires": "Mon, 24 Dec 2012 01:34:25 GMT" + }, + { + "last-modified": "Wed, 25 Jul 2012 11:42:45 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=19834480" + }, + { + "expires": "Fri, 21 Jun 2013 02:31:52 GMT" + }, + { + "last-modified": "Tue, 02 Aug 2011 09:47:52 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=11268" + }, + { + "expires": "Sat, 03 Nov 2012 16:05:00 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 06:41:35 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5616267" + }, + { + "expires": "Mon, 07 Jan 2013 13:01:39 GMT" + }, + { + "last-modified": "Tue, 26 Jun 2012 12:48:17 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=7263532" + }, + { + "expires": "Sat, 26 Jan 2013 14:36:04 GMT" + }, + { + "last-modified": "Sat, 19 May 2012 09:39:27 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:57:08 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "94544" + }, + { + "cache-control": "max-age=31536000" + }, + { + "etag": "\"1031174008914679718\"" + }, + { + "expires": "Tue, 20 Aug 2013 13:41:19 GMT" + }, + { + "last-modified": "Sun, 08 Jul 2012 14:17:09 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/gif" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "723" + }, + { + "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "tracecode": "34277428450405149450110320" + }, + { + "content-encoding": "gzip" + }, + { + "set-cookie": "wise_device=0; expires=Sun, 03-Nov-2013 12:57:07 GMT; path=/" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "3728" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "987" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "3108" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Mon, 29 Oct 2012 09:07:40 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "598" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "717" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "973" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "386" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Wed, 25 Jul 2012 07:00:44 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-length": "584" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "text/css" + }, + { + "last-modified": "Wed, 30 May 2012 03:14:35 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "429" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "2725" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "last-modified": "Thu, 14 Oct 2010 10:10:45 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:10 GMT" + }, + { + "cache-control": "max-age=2592000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1633" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "733" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1647" + }, + { + "last-modified": "Fri, 02 Nov 2012 10:49:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1217631" + }, + { + "expires": "Sat, 17 Nov 2012 15:11:03 GMT" + }, + { + "last-modified": "Sat, 06 Oct 2012 08:29:30 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4935379" + }, + { + "expires": "Sun, 30 Dec 2012 15:53:31 GMT" + }, + { + "last-modified": "Thu, 12 Jul 2012 07:04:33 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=94090" + }, + { + "expires": "Sun, 04 Nov 2012 15:05:22 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 08:40:52 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=268205" + }, + { + "expires": "Tue, 06 Nov 2012 15:27:17 GMT" + }, + { + "last-modified": "Sun, 28 Oct 2012 07:57:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3501790" + }, + { + "expires": "Fri, 14 Dec 2012 01:40:22 GMT" + }, + { + "last-modified": "Tue, 14 Aug 2012 11:30:52 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1089367" + }, + { + "expires": "Fri, 16 Nov 2012 03:33:19 GMT" + }, + { + "last-modified": "Tue, 09 Oct 2012 07:44:57 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5175917" + }, + { + "expires": "Wed, 02 Jan 2013 10:42:29 GMT" + }, + { + "last-modified": "Fri, 06 Jul 2012 17:26:38 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2826947" + }, + { + "expires": "Thu, 06 Dec 2012 06:12:59 GMT" + }, + { + "last-modified": "Thu, 30 Aug 2012 02:25:38 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "560" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2850" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1196" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "1804" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1320" + }, + { + "last-modified": "Wed, 30 May 2012 03:19:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Wed, 30 May 2012 03:19:18 GMT" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1990" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=14263076" + }, + { + "expires": "Wed, 17 Apr 2013 14:55:08 GMT" + }, + { + "last-modified": "Fri, 09 Dec 2011 09:01:20 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2086351" + }, + { + "expires": "Tue, 27 Nov 2012 16:29:43 GMT" + }, + { + "last-modified": "Sun, 16 Sep 2012 05:52:10 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=6392807" + }, + { + "expires": "Wed, 16 Jan 2013 12:43:59 GMT" + }, + { + "last-modified": "Fri, 08 Jun 2012 13:23:38 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4373528" + }, + { + "expires": "Mon, 24 Dec 2012 03:49:20 GMT" + }, + { + "last-modified": "Wed, 25 Jul 2012 07:12:56 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=960053" + }, + { + "expires": "Wed, 14 Nov 2012 15:38:05 GMT" + }, + { + "last-modified": "Fri, 12 Oct 2012 07:35:25 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1446556" + }, + { + "expires": "Tue, 20 Nov 2012 06:46:28 GMT" + }, + { + "last-modified": "Mon, 01 Oct 2012 01:18:39 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=13730089" + }, + { + "expires": "Thu, 11 Apr 2013 10:52:01 GMT" + }, + { + "last-modified": "Wed, 21 Dec 2011 17:07:33 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4447089" + }, + { + "expires": "Tue, 25 Dec 2012 00:15:21 GMT" + }, + { + "last-modified": "Mon, 23 Jul 2012 14:20:53 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1048930" + }, + { + "expires": "Thu, 15 Nov 2012 16:19:22 GMT" + }, + { + "last-modified": "Wed, 10 Oct 2012 06:12:51 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"4013610198\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 20 Jun 2012 16:39:57 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1828" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "BWS/1.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=23765568" + }, + { + "expires": "Mon, 05 Aug 2013 14:30:00 GMT" + }, + { + "last-modified": "Tue, 03 May 2011 09:51:35 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "9466" + }, + { + "last-modified": "Wed, 25 Jul 2012 06:58:47 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2736291" + }, + { + "expires": "Wed, 05 Dec 2012 05:02:03 GMT" + }, + { + "last-modified": "Sat, 01 Sep 2012 04:47:30 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=7202517" + }, + { + "expires": "Fri, 25 Jan 2013 21:39:09 GMT" + }, + { + "last-modified": "Sun, 20 May 2012 19:33:18 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=962816" + }, + { + "expires": "Wed, 14 Nov 2012 16:24:09 GMT" + }, + { + "last-modified": "Fri, 12 Oct 2012 06:03:21 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=28898351" + }, + { + "expires": "Fri, 04 Oct 2013 00:16:24 GMT" + }, + { + "last-modified": "Tue, 04 Jan 2011 14:18:50 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=26910239" + }, + { + "expires": "Wed, 11 Sep 2013 00:01:12 GMT" + }, + { + "last-modified": "Sat, 19 Feb 2011 14:49:14 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=314449" + }, + { + "expires": "Wed, 07 Nov 2012 04:18:02 GMT" + }, + { + "last-modified": "Sat, 27 Oct 2012 06:15:34 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=17303680" + }, + { + "expires": "Wed, 22 May 2013 19:31:53 GMT" + }, + { + "last-modified": "Thu, 29 Sep 2011 23:47:53 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=8742316" + }, + { + "expires": "Tue, 12 Feb 2013 17:22:29 GMT" + }, + { + "last-modified": "Sun, 15 Apr 2012 04:06:41 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=951041" + }, + { + "expires": "Wed, 14 Nov 2012 13:07:54 GMT" + }, + { + "last-modified": "Fri, 12 Oct 2012 12:35:50 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12357995" + }, + { + "expires": "Tue, 26 Mar 2013 13:43:48 GMT" + }, + { + "last-modified": "Sun, 22 Jan 2012 11:24:02 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "Keep-Alive" + }, + { + "content-length": "30289" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:14:30 GMT" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Apache" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "tracecode": "34277428450405149450110320" + }, + { + "content-encoding": "gzip" + }, + { + "set-cookie": "wise_device=0; expires=Sun, 03-Nov-2013 12:57:07 GMT; path=/" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=6924353" + }, + { + "expires": "Tue, 22 Jan 2013 16:23:06 GMT" + }, + { + "last-modified": "Sun, 27 May 2012 06:05:27 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=35998348" + }, + { + "expires": "Wed, 25 Dec 2013 04:29:41 GMT" + }, + { + "last-modified": "Sat, 24 Jul 2010 05:52:16 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=403161" + }, + { + "expires": "Thu, 08 Nov 2012 04:56:34 GMT" + }, + { + "last-modified": "Thu, 25 Oct 2012 04:58:30 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=11795987" + }, + { + "expires": "Wed, 20 Mar 2013 01:37:00 GMT" + }, + { + "last-modified": "Sat, 04 Feb 2012 11:37:39 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4466678" + }, + { + "expires": "Tue, 25 Dec 2012 05:41:51 GMT" + }, + { + "last-modified": "Mon, 23 Jul 2012 03:27:57 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4380824" + }, + { + "expires": "Mon, 24 Dec 2012 05:50:57 GMT" + }, + { + "last-modified": "Wed, 25 Jul 2012 03:09:45 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4370018" + }, + { + "expires": "Mon, 24 Dec 2012 02:50:51 GMT" + }, + { + "last-modified": "Wed, 25 Jul 2012 09:09:57 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=22046695" + }, + { + "expires": "Tue, 16 Jul 2013 17:02:08 GMT" + }, + { + "last-modified": "Sun, 12 Jun 2011 04:47:22 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "etag": "\"1795935374\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 20 Sep 2012 06:30:31 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "490" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1813409" + }, + { + "expires": "Sat, 24 Nov 2012 12:40:42 GMT" + }, + { + "last-modified": "Sat, 22 Sep 2012 13:30:14 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2381150" + }, + { + "expires": "Sat, 01 Dec 2012 02:23:03 GMT" + }, + { + "last-modified": "Sun, 09 Sep 2012 10:05:33 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12085408" + }, + { + "expires": "Sat, 23 Mar 2013 10:00:41 GMT" + }, + { + "last-modified": "Sat, 28 Jan 2012 18:50:17 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=7660325" + }, + { + "expires": "Thu, 31 Jan 2013 04:49:18 GMT" + }, + { + "last-modified": "Thu, 10 May 2012 05:13:02 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=20831903" + }, + { + "expires": "Tue, 02 Jul 2013 15:35:36 GMT" + }, + { + "last-modified": "Sun, 10 Jul 2011 07:40:26 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:12 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "42293" + }, + { + "last-modified": "Wed, 30 May 2012 03:19:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:57:12 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "accept-ranges": "bytes" + }, + { + "transfer-encoding": "chunked" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=13227345" + }, + { + "expires": "Fri, 05 Apr 2013 15:12:58 GMT" + }, + { + "last-modified": "Mon, 02 Jan 2012 08:25:43 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5658505" + }, + { + "expires": "Tue, 08 Jan 2013 00:45:38 GMT" + }, + { + "last-modified": "Mon, 25 Jun 2012 13:20:23 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1397477" + }, + { + "expires": "Mon, 19 Nov 2012 17:08:30 GMT" + }, + { + "last-modified": "Tue, 02 Oct 2012 04:34:38 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3108210" + }, + { + "expires": "Sun, 09 Dec 2012 12:20:43 GMT" + }, + { + "last-modified": "Thu, 23 Aug 2012 14:10:13 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1080824" + }, + { + "expires": "Fri, 16 Nov 2012 01:10:57 GMT" + }, + { + "last-modified": "Tue, 09 Oct 2012 12:29:45 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=10544861" + }, + { + "expires": "Tue, 05 Mar 2013 14:04:54 GMT" + }, + { + "last-modified": "Sun, 04 Mar 2012 10:41:50 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=9336177" + }, + { + "expires": "Tue, 19 Feb 2013 14:20:10 GMT" + }, + { + "last-modified": "Sun, 01 Apr 2012 10:11:18 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=947069" + }, + { + "expires": "Wed, 14 Nov 2012 12:01:43 GMT" + }, + { + "last-modified": "Fri, 12 Oct 2012 14:48:15 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1473803" + }, + { + "expires": "Tue, 20 Nov 2012 14:20:37 GMT" + }, + { + "last-modified": "Sun, 30 Sep 2012 10:10:28 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1395562" + }, + { + "expires": "Mon, 19 Nov 2012 16:36:36 GMT" + }, + { + "last-modified": "Tue, 02 Oct 2012 05:38:29 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4082149" + }, + { + "expires": "Thu, 20 Dec 2012 18:53:02 GMT" + }, + { + "last-modified": "Wed, 01 Aug 2012 01:05:35 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4020129" + }, + { + "expires": "Thu, 20 Dec 2012 01:39:23 GMT" + }, + { + "last-modified": "Thu, 02 Aug 2012 11:32:55 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=30533221" + }, + { + "expires": "Tue, 22 Oct 2013 22:24:15 GMT" + }, + { + "last-modified": "Sat, 27 Nov 2010 18:03:12 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=9250886" + }, + { + "expires": "Mon, 18 Feb 2013 14:38:40 GMT" + }, + { + "last-modified": "Tue, 03 Apr 2012 09:34:21 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=7796153" + }, + { + "expires": "Fri, 01 Feb 2013 18:33:07 GMT" + }, + { + "last-modified": "Mon, 07 May 2012 01:45:28 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12403487" + }, + { + "expires": "Wed, 27 Mar 2013 02:22:01 GMT" + }, + { + "last-modified": "Sat, 21 Jan 2012 10:07:40 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=342416" + }, + { + "expires": "Wed, 07 Nov 2012 12:04:10 GMT" + }, + { + "last-modified": "Fri, 26 Oct 2012 14:43:22 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=13044961" + }, + { + "expires": "Wed, 03 Apr 2013 12:33:15 GMT" + }, + { + "last-modified": "Fri, 06 Jan 2012 13:45:12 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=90589" + }, + { + "expires": "Sun, 04 Nov 2012 14:07:03 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 10:37:35 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=13128536" + }, + { + "expires": "Thu, 04 Apr 2013 11:46:10 GMT" + }, + { + "last-modified": "Wed, 04 Jan 2012 15:19:22 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3557238" + }, + { + "expires": "Fri, 14 Dec 2012 17:04:32 GMT" + }, + { + "last-modified": "Mon, 13 Aug 2012 04:42:37 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=2348339" + }, + { + "expires": "Fri, 30 Nov 2012 17:16:13 GMT" + }, + { + "last-modified": "Mon, 10 Sep 2012 04:19:15 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=303065" + }, + { + "expires": "Wed, 07 Nov 2012 01:08:19 GMT" + }, + { + "last-modified": "Sat, 27 Oct 2012 12:35:04 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3713169" + }, + { + "expires": "Sun, 16 Dec 2012 12:23:23 GMT" + }, + { + "last-modified": "Thu, 09 Aug 2012 14:04:55 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3556632" + }, + { + "expires": "Fri, 14 Dec 2012 16:54:26 GMT" + }, + { + "last-modified": "Mon, 13 Aug 2012 05:02:50 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4793201" + }, + { + "expires": "Sat, 29 Dec 2012 00:23:55 GMT" + }, + { + "last-modified": "Sun, 15 Jul 2012 14:03:52 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=488079" + }, + { + "expires": "Fri, 09 Nov 2012 04:31:53 GMT" + }, + { + "last-modified": "Tue, 23 Oct 2012 05:47:55 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=12998284" + }, + { + "expires": "Tue, 02 Apr 2013 23:35:18 GMT" + }, + { + "last-modified": "Sat, 07 Jan 2012 15:41:05 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=38194284" + }, + { + "expires": "Sun, 19 Jan 2014 14:28:38 GMT" + }, + { + "last-modified": "Thu, 03 Jun 2010 09:54:26 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:13 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "17574" + }, + { + "last-modified": "Fri, 26 Oct 2012 03:00:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:57:13 GMT" + }, + { + "cache-control": "max-age=3600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1010448" + }, + { + "expires": "Thu, 15 Nov 2012 05:38:02 GMT" + }, + { + "last-modified": "Thu, 11 Oct 2012 03:35:37 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=573690" + }, + { + "expires": "Sat, 10 Nov 2012 04:18:44 GMT" + }, + { + "last-modified": "Sun, 21 Oct 2012 06:14:13 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=9690556" + }, + { + "expires": "Sat, 23 Feb 2013 16:46:30 GMT" + }, + { + "last-modified": "Sat, 24 Mar 2012 05:18:41 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=20727056" + }, + { + "expires": "Mon, 01 Jul 2013 10:28:10 GMT" + }, + { + "last-modified": "Tue, 12 Jul 2011 17:55:22 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5867076" + }, + { + "expires": "Thu, 10 Jan 2013 10:41:50 GMT" + }, + { + "last-modified": "Wed, 20 Jun 2012 17:28:01 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1938815" + }, + { + "expires": "Sun, 25 Nov 2012 23:30:49 GMT" + }, + { + "last-modified": "Wed, 19 Sep 2012 15:50:04 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:14 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=25417039" + }, + { + "expires": "Sat, 24 Aug 2013 17:14:33 GMT" + }, + { + "last-modified": "Sat, 26 Mar 2011 04:22:35 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1258204" + }, + { + "expires": "Sun, 18 Nov 2012 02:27:19 GMT" + }, + { + "last-modified": "Fri, 05 Oct 2012 09:57:06 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1855684" + }, + { + "expires": "Sun, 25 Nov 2012 00:25:19 GMT" + }, + { + "last-modified": "Fri, 21 Sep 2012 14:01:06 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=6489659" + }, + { + "expires": "Thu, 17 Jan 2013 15:38:14 GMT" + }, + { + "last-modified": "Wed, 06 Jun 2012 07:35:17 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4972705" + }, + { + "expires": "Mon, 31 Dec 2012 02:15:40 GMT" + }, + { + "last-modified": "Wed, 11 Jul 2012 10:20:25 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4075979" + }, + { + "expires": "Thu, 20 Dec 2012 17:10:14 GMT" + }, + { + "last-modified": "Wed, 01 Aug 2012 04:31:16 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "BWS/1.0" + }, + { + "content-length": "16" + }, + { + "content-type": "text/html;charset=gbk" + }, + { + "cache-control": "private" + }, + { + "set-cookie": "BDRCVFR[RQbEFtOPS6t]=mbxnW11j9Dfmh7GuZR8mvqV; path=/; domain=rp.baidu.com" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "BWS/1.0" + }, + { + "content-length": "16" + }, + { + "content-type": "text/html;charset=gbk" + }, + { + "cache-control": "private" + }, + { + "set-cookie": "BDRCVFR[74hAi0as9Oc]=mbxnW11j9Dfmh7GuZR8mvqV; path=/; domain=rp.baidu.com" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "BWS/1.0" + }, + { + "content-length": "16" + }, + { + "content-type": "text/html;charset=gbk" + }, + { + "cache-control": "private" + }, + { + "set-cookie": "BDRCVFR[INlq_Cf3RCm]=mbxnW11j9Dfmh7GuZR8mvqV; path=/; domain=rp.baidu.com" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "BWS/1.0" + }, + { + "content-length": "16" + }, + { + "content-type": "text/html;charset=gbk" + }, + { + "cache-control": "private" + }, + { + "set-cookie": "BDRCVFR[wqXIM55hsyY]=mbxnW11j9Dfmh7GuZR8mvqV; path=/; domain=rp.baidu.com" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "content-type": "text/html" + }, + { + "content-length": "17574" + }, + { + "last-modified": "Sat Nov 3 20:57:15 2012" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 26 Jul 1997 05:00:00 GMT" + }, + { + "cache-control": "post-check=0, pre-check=0" + }, + { + "transfer-encoding": "chunked" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=433162" + }, + { + "expires": "Thu, 08 Nov 2012 13:16:37 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 12:18:30 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=701481" + }, + { + "expires": "Sun, 11 Nov 2012 15:48:36 GMT" + }, + { + "last-modified": "Thu, 18 Oct 2012 07:14:33 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=473366" + }, + { + "expires": "Fri, 09 Nov 2012 00:26:41 GMT" + }, + { + "last-modified": "Tue, 23 Oct 2012 13:58:23 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=5523078" + }, + { + "expires": "Sun, 06 Jan 2013 11:08:33 GMT" + }, + { + "last-modified": "Thu, 28 Jun 2012 16:34:39 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=16759229" + }, + { + "expires": "Thu, 16 May 2013 12:17:44 GMT" + }, + { + "last-modified": "Wed, 12 Oct 2011 14:16:17 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=4189499" + }, + { + "expires": "Sat, 22 Dec 2012 00:42:14 GMT" + }, + { + "last-modified": "Sun, 29 Jul 2012 13:27:17 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "close" + }, + { + "etag": "\"2607371477\"" + }, + { + "last-modified": "Tue, 18 Sep 2012 05:49:17 GMT" + }, + { + "expires": "Sun, 17 Mar 2013 06:26:16 GMT" + }, + { + "cache-control": "max-age=15552000" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "close" + }, + { + "etag": "\"2063226227\"" + }, + { + "last-modified": "Fri, 02 Nov 2012 10:39:26 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:09:38 GMT" + }, + { + "cache-control": "max-age=1800" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=1345881" + }, + { + "expires": "Mon, 19 Nov 2012 02:48:36 GMT" + }, + { + "last-modified": "Wed, 03 Oct 2012 09:14:33 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=96063" + }, + { + "expires": "Sun, 04 Nov 2012 15:38:18 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 07:35:08 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=3617766" + }, + { + "expires": "Sat, 15 Dec 2012 09:53:21 GMT" + }, + { + "last-modified": "Sat, 11 Aug 2012 19:05:03 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=11496580" + }, + { + "expires": "Sat, 16 Mar 2013 14:26:55 GMT" + }, + { + "last-modified": "Sat, 11 Feb 2012 09:57:55 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "server": "apache 1.1.26.0" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=307195" + }, + { + "expires": "Wed, 07 Nov 2012 02:17:10 GMT" + }, + { + "last-modified": "Sat, 27 Oct 2012 10:17:24 GMT" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:57:15 GMT" + }, + { + "content-type": "text/css" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "close" + }, + { + "etag": "\"618192838\"" + }, + { + "last-modified": "Thu, 01 Nov 2012 12:49:53 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "JSP2/1.0.2" + }, + { + "date": "Sat, 03 Nov 2012 12:57:16 GMT" + }, + { + "content-type": "image/png" + }, + { + "connection": "close" + }, + { + "content-length": "9799" + }, + { + "etag": "\"2773371803\"" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 30 Oct 2012 03:58:12 GMT" + }, + { + "expires": "Fri, 09 Nov 2012 09:54:56 GMT" + }, + { + "cache-control": "max-age=604800" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_23.json b/jetty-http2/http2-hpack/src/test/resources/data/story_23.json new file mode 100644 index 00000000000..935e29dc70d --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_23.json @@ -0,0 +1,13406 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "301" + }, + { + "date": "Sat, 03 Nov 2012 13:37:10 GMT" + }, + { + "server": "Apache/2.2.22 (Unix)" + }, + { + "set-cookie": "BBC-UID=557049b5114e60f649a3590541375a237274de5c1020f1118262d353e424f5650Mozilla%2f5%2e0%20%28Macintosh%3b%20Intel%20Mac%20OS%20X%2010%2e8%3b%20rv%3a16%2e0%29%20Gecko%2f20100101%20Firefox%2f16%2e0; expires=Sun, 03-Nov-13 13:37:10 GMT; path=/; domain=.bbc.co.uk;" + }, + { + "location": "http://www.bbc.co.uk/" + }, + { + "content-length": "229" + }, + { + "connection": "close" + }, + { + "content-type": "text/html; charset=iso-8859-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "cache-control": "private, max-age=60" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "etag": "\"dfc69d0362a1518353bddd8fa0dcc7cf-49cffe7f817cb754d3241794c0a3e991\"" + }, + { + "x-pal-host": "pal047.cwwtf.bbc.co.uk:80" + }, + { + "content-length": "25186" + }, + { + "date": "Sat, 03 Nov 2012 13:37:11 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "PASS (non-cacheable)" + }, + { + "x-cache-age": "33" + }, + { + "vary": "X-CDN" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:12 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Mon, 15 Oct 2012 10:42:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=900" + }, + { + "expires": "Sat, 03 Nov 2012 13:52:11 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2414" + }, + { + "age": "0" + }, + { + "keep-alive": "timeout=4, max=175" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "cache-control": "max-age=86400" + }, + { + "content-type": "image/x-icon" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Sun, 04 Nov 2012 13:37:12 GMT" + }, + { + "etag": "\"dfc69d0362a1518353bddd8fa0dcc7cf-49cffe7f817cb754d3241794c0a3e991\"" + }, + { + "x-pal-host": "pal047.cwwtf.bbc.co.uk:80" + }, + { + "content-length": "958" + }, + { + "date": "Sat, 03 Nov 2012 13:37:12 GMT" + }, + { + "connection": "Keep-Alive" + }, + { + "x-cache-action": "PASS (non-cacheable)" + }, + { + "x-cache-age": "33" + }, + { + "vary": "X-CDN" + }, + { + "last-modified": "Wed, 28 Jun 2006 14:32:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "0" + }, + { + "keep-alive": "timeout=4, max=190" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 05 May 2011 09:15:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4786" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=30845970" + }, + { + "expires": "Sat, 26 Oct 2013 13:56:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "etag": "\"d1a-4af7eb4dd8880\"" + }, + { + "expires": "Tue, 13 Nov 2012 11:52:05 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 17 Oct 2011 13:37:22 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1227" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "etag": "\"677-4af7eb4bf0400\"" + }, + { + "expires": "Tue, 13 Nov 2012 11:49:51 GMT" + }, + { + "cache-control": "max-age=2592000" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 17 Oct 2011 13:37:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "644" + }, + { + "content-type": "text/css" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Mon, 29 Oct 2012 13:31:55 GMT" + }, + { + "etag": "\"3c9-4cd32b163a8c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 31 Oct 2013 08:47:52 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "418" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Mon, 29 Oct 2012 13:31:55 GMT" + }, + { + "etag": "\"217-4cd32b163a8c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 31 Oct 2013 08:48:03 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "211" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 11 Oct 2012 10:08:28 GMT" + }, + { + "etag": "\"7316-4cbc5c0a6df00\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 24 Oct 2013 08:20:52 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5855" + }, + { + "content-type": "text/css" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Mon, 29 Oct 2012 13:33:03 GMT" + }, + { + "etag": "\"714c-4cd32b57141c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 31 Oct 2013 08:48:07 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5891" + }, + { + "content-type": "text/css" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 16 Nov 2011 15:42:16 GMT" + }, + { + "etag": "\"5ec2-4b1dbf2c82600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Tue, 17 Sep 2013 11:45:35 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7383" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 11 Oct 2012 10:08:26 GMT" + }, + { + "etag": "\"41d9-4cbc5c0885a80\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 24 Oct 2013 08:21:11 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "content-length": "5723" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Mon, 29 Oct 2012 13:32:01 GMT" + }, + { + "etag": "\"9029-4cd32b1bf3640\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 31 Oct 2013 08:47:52 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11967" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 26 Apr 2010 14:22:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "916" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=27418917" + }, + { + "expires": "Mon, 16 Sep 2013 21:59:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 06 Jul 2011 17:14:05 GMT" + }, + { + "etag": "\"20a0c-4a769ba3ff140\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Tue, 17 Sep 2013 11:50:03 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "37892" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:14 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 26 Apr 2010 14:18:35 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "31308" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=27418893" + }, + { + "expires": "Mon, 16 Sep 2013 21:58:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:14 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://www.googleadservices.com/pagead/p3p.xml\", CP=\"NOI DEV PSA PSD IVA IVD OTP OUR OTR IND OTC\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "etag": "16031183393755591049" + }, + { + "date": "Sat, 03 Nov 2012 12:45:54 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:45:54 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-disposition": "attachment" + }, + { + "content-encoding": "gzip" + }, + { + "server": "cafe" + }, + { + "content-length": "11145" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "3084" + }, + { + "cache-control": "public, max-age=3600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Mon, 29 Oct 2012 13:31:56 GMT" + }, + { + "etag": "\"722a-4cd32b172eb00\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 31 Oct 2013 08:48:06 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5813" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "302" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "302" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:19 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Tue, 08 May 2012 20:06:18 GMT" + }, + { + "date": "Fri, 02 Nov 2012 14:30:10 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:30:10 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "43" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "83229" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:37:19 GMT" + }, + { + "cache-control": "max-age=86400, private" + }, + { + "expires": "Sun, 04 Nov 2012 13:37:19 GMT" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "x-proc-data": "pd3-bgas02-0" + }, + { + "content-type": "application/javascript;charset=ISO-8859-1" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 03 Oct 2012 14:20:11 GMT" + }, + { + "etag": "\"1fbb-4cb2856215cc0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=2592000" + }, + { + "expires": "Fri, 30 Nov 2012 15:42:45 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3254" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT" + }, + { + "etag": "\"3fc-4cbc5c069d600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 24 Oct 2013 08:21:03 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1020" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT" + }, + { + "etag": "\"bc-4cbc5c069d600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 24 Oct 2013 08:20:59 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "188" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 27 Sep 2012 10:15:51 GMT" + }, + { + "etag": "\"293-4caac394743c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 03 Oct 2013 09:51:46 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "content-length": "659" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "etag": "\"11e-4caac394743c0\"" + }, + { + "expires": "Thu, 03 Oct 2013 09:51:45 GMT" + }, + { + "cache-control": "max-age=31536000" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 27 Sep 2012 10:15:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "286" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "etag": "\"25d-4caac394743c0\"" + }, + { + "expires": "Thu, 03 Oct 2013 09:51:56 GMT" + }, + { + "cache-control": "max-age=31536000" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 27 Sep 2012 10:15:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "605" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:19:32 GMT" + }, + { + "etag": "\"121f4-4cd5e1b17b100\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31470349" + }, + { + "expires": "Thu, 31 Oct 2013 17:19:32 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10750" + }, + { + "content-type": "text/css" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "2378" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:19 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Fri, 24 Jun 2011 10:14:39 GMT" + }, + { + "date": "Fri, 02 Nov 2012 22:58:53 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 22:58:53 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "12034" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "52707" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "308" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "308" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\"" + }, + { + "set-cookie": "s1=50951E1074D40255; expires=Thu, 02-Nov-2017 13:37:20 GMT; path=/; domain=.bbc.co.uk" + }, + { + "location": "http://sa.bbc.co.uk/bbc/bbc/s?name=home.page&ns_m2=yes&ns_setsiteck=50951E1074D40255&geo_edition=int&pal_route=default&ml_name=barlesque&app_type=web&language=en-GB&ml_version=0.14.2&pal_webapp=wwhomepage&bbc_mc=not_set&screen_resolution=1366x768&blq_s=3.5&blq_r=3.5&blq_v=default-worldwide&ns__t=1351949839865&ns_c=UTF-8&ns_ti=BBC%20-%20Homepage&ns_jspageurl=http%3A//www.bbc.co.uk/&ns_referrer=" + }, + { + "content-length": "656" + }, + { + "connection": "close" + }, + { + "content-type": "text/html; charset=iso-8859-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:19:32 GMT" + }, + { + "etag": "\"608f-4cd5e1b17b100\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31470342" + }, + { + "expires": "Thu, 31 Oct 2013 17:19:32 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6150" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT" + }, + { + "etag": "\"223-4cbc5c069d600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 24 Oct 2013 08:20:57 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "547" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "308" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT" + }, + { + "etag": "\"89f-4cbc5c069d600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 24 Oct 2013 08:20:51 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2207" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\"" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "308" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Mon, 29 Oct 2012 13:32:08 GMT" + }, + { + "etag": "\"11d21-4cd32b22a0600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 31 Oct 2013 08:48:10 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "24284" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "3291" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "last-modified": "Wed, 19 Sep 2012 18:25:49 GMT" + }, + { + "date": "Fri, 02 Nov 2012 20:14:11 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 20:14:11 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "1581" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "62589" + }, + { + "cache-control": "public, max-age=86400" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT" + }, + { + "etag": "\"1b7f-4cd5e1abc2380\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31470341" + }, + { + "expires": "Thu, 31 Oct 2013 17:19:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7039" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT" + }, + { + "etag": "\"20a3-4cd5e1abc2380\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31470356" + }, + { + "expires": "Thu, 31 Oct 2013 17:19:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8355" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "308" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT" + }, + { + "etag": "\"3038-4cd5e1abc2380\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31470335" + }, + { + "expires": "Thu, 31 Oct 2013 17:19:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "content-length": "12344" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/javascript" + }, + { + "last-modified": "Fri, 07 Sep 2012 16:46:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 10:27:06 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 10:27:06 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "23913" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "11414" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT" + }, + { + "etag": "\"1ff0-4cd5e1abc2380\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31470356" + }, + { + "expires": "Thu, 31 Oct 2013 17:19:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8176" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "308" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Mon, 03 Nov 2014 06:54:04 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 06:50:43 GMT" + }, + { + "content-length": "3810" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Fri, 31 Oct 2014 21:56:00 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Wed, 31 Oct 2012 21:51:59 GMT" + }, + { + "content-length": "5049" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Mon, 03 Nov 2014 09:47:13 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 09:31:24 GMT" + }, + { + "content-length": "5071" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Thu, 19 Jul 2012 22:49:47 GMT" + }, + { + "date": "Fri, 02 Nov 2012 22:03:55 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 22:03:55 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "31936" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "56006" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "image/gif" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "cafe" + }, + { + "content-length": "42" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT" + }, + { + "etag": "\"323-4cd5e1abc2380\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31470350" + }, + { + "expires": "Thu, 31 Oct 2013 17:19:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "803" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "347" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 06 Jul 2011 17:14:01 GMT" + }, + { + "etag": "\"1a56e-4a769ba02e840\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Tue, 17 Sep 2013 11:50:28 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "30642" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Tue, 30 Oct 2012 14:27:29 GMT" + }, + { + "date": "Fri, 02 Nov 2012 20:29:16 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 20:29:16 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "18065" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "61685" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLuB86QsXkGiDUw6LAw6IpFSRlNUwBT4lFpER0UXYGEV+3P4; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:37:21 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas08-1" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Mon, 03 Nov 2014 12:03:34 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 11:02:09 GMT" + }, + { + "content-length": "13746" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT" + }, + { + "etag": "\"136-4cd5e1abc2380\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31470294" + }, + { + "expires": "Thu, 31 Oct 2013 17:19:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "content-length": "310" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Mon, 03 Nov 2014 08:07:24 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 08:04:03 GMT" + }, + { + "content-length": "10701" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 02 Nov 2014 11:46:30 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:37:23 GMT" + }, + { + "content-length": "4375" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 02 Nov 2014 03:14:26 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 02 Nov 2012 03:10:05 GMT" + }, + { + "content-length": "3965" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 02 Nov 2014 12:49:53 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 02 Nov 2012 12:39:23 GMT" + }, + { + "content-length": "4844" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:23:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31490899" + }, + { + "expires": "Sat, 02 Nov 2013 13:28:30 GMT" + }, + { + "content-length": "18949" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Fri, 02 Nov 2012 17:01:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 02:00:11 GMT" + }, + { + "content-length": "25085" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:30:25 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=31493423" + }, + { + "expires": "Sat, 02 Nov 2013 14:10:58 GMT" + }, + { + "content-length": "27938" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 02 Nov 2014 05:49:17 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:43:46 GMT" + }, + { + "content-length": "5569" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:37:22 GMT" + }, + { + "server": "Omniture DC/2.0.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "set-cookie": "s_vi=[CS]v1|284A8F0905160D8B-600001A1C0108CD4[CE]; Expires=Thu, 2 Nov 2017 13:37:22 GMT; Domain=sa.bbc.com; Path=/" + }, + { + "location": "http://sa.bbc.com/b/ss/bbcwglobalprod/1/H.22.1/s0268806509673?AQB=1&pccr=true&vidn=284A8F0905160D8B-600001A1C0108CD4&&ndh=1&t=3%2F10%2F2012%209%3A37%3A21%206%20240&vmt=4F9A739C&vmf=bbc.112.2o7.net&ce=UTF-8&cdp=3&pageName=bbc%20%7C%20homepage&g=http%3A%2F%2Fwww.bbc.co.uk%2F&cc=USD&ch=homepage&events=event2&h1=bbc%7Chomepage&v2=D%3DpageName&c5=INDEX&v5=D%3Dc5&c6=homepage&v6=D%3Dc6&c11=saturday%7C1%3A30pm&c15=%2F&v15=D%3Dc15&c17=bbc%20%7C%20homepage&v17=D%3Dc17&c31=HTML&v31=D%3Dc31&c32=Not%20available&v32=D%3Dc32&v49=Direct%20Load&c53=www.bbc.co.uk&v53=D%3Dc53&c54=http%3A%2F%2Fwww.bbc.co.uk&v54=D%3Dc54&c55=bbc.com&v55=D%3Dc55&c56=D%3DpageName&v56=D%3Dc56&c57=yes&v57=D%3Dc57&c62=wpp%7Cldb%7Cm08%7Cm2l%7Cm6i%7Cm1f%7Cmpu%7Cm29%7Cm4t%7Cm80&v62=D%3Dc62&s=1366x768&c=24&j=1.7&v=Y&k=Y&bw=994&bh=649&p=Java%20Applet%20Plug-in%3BQuickTime%20Plug-in%207.7.1%3B&AQE=1" + }, + { + "x-c": "ms-4.4.9" + }, + { + "expires": "Fri, 02 Nov 2012 13:37:22 GMT" + }, + { + "last-modified": "Sun, 04 Nov 2012 13:37:22 GMT" + }, + { + "cache-control": "no-cache, no-store, max-age=0, no-transform, private" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA OUR IND COM NAV STA\"" + }, + { + "xserver": "www614" + }, + { + "content-length": "0" + }, + { + "keep-alive": "timeout=15" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/plain" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=86400" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 04 Nov 2012 09:02:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 02 Nov 2012 09:46:49 GMT" + }, + { + "content-length": "2041" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"c82a-4cd8003bbf440\"" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=86400" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 04 Nov 2012 09:34:34 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:33:07 GMT" + }, + { + "content-length": "5173" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"3ca55-4cd817fe482c0\"" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:22 GMT" + }, + { + "server": "Omniture DC/2.0.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "set-cookie": "s_vi=[CS]v1|284A8F0905160D8B-600001A1C0108CD4[CE]; Expires=Thu, 2 Nov 2017 13:37:22 GMT; Domain=sa.bbc.com; Path=/" + }, + { + "location": "http://sa.bbc.com/b/ss/bbcwglobalprod/1/H.22.1/s0268806509673?AQB=1&pccr=true&vidn=284A8F0905160D8B-600001A1C0108CD4&&ndh=1&t=3%2F10%2F2012%209%3A37%3A21%206%20240&vmt=4F9A739C&vmf=bbc.112.2o7.net&ce=UTF-8&cdp=3&pageName=bbc%20%7C%20homepage&g=http%3A%2F%2Fwww.bbc.co.uk%2F&cc=USD&ch=homepage&events=event2&h1=bbc%7Chomepage&v2=D%3DpageName&c5=INDEX&v5=D%3Dc5&c6=homepage&v6=D%3Dc6&c11=saturday%7C1%3A30pm&c15=%2F&v15=D%3Dc15&c17=bbc%20%7C%20homepage&v17=D%3Dc17&c31=HTML&v31=D%3Dc31&c32=Not%20available&v32=D%3Dc32&v49=Direct%20Load&c53=www.bbc.co.uk&v53=D%3Dc53&c54=http%3A%2F%2Fwww.bbc.co.uk&v54=D%3Dc54&c55=bbc.com&v55=D%3Dc55&c56=D%3DpageName&v56=D%3Dc56&c57=yes&v57=D%3Dc57&c62=wpp%7Cldb%7Cm08%7Cm2l%7Cm6i%7Cm1f%7Cmpu%7Cm29%7Cm4t%7Cm80&v62=D%3Dc62&s=1366x768&c=24&j=1.7&v=Y&k=Y&bw=994&bh=649&p=Java%20Applet%20Plug-in%3BQuickTime%20Plug-in%207.7.1%3B&AQE=1" + }, + { + "x-c": "ms-4.4.9" + }, + { + "expires": "Fri, 02 Nov 2012 13:37:22 GMT" + }, + { + "last-modified": "Sun, 04 Nov 2012 13:37:22 GMT" + }, + { + "cache-control": "no-cache, no-store, max-age=0, no-transform, private" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA OUR IND COM NAV STA\"" + }, + { + "xserver": "www620" + }, + { + "content-length": "43" + }, + { + "keep-alive": "timeout=15" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + }, + { + "etag": "\"50951E12-5F83-53505C0B\"" + }, + { + "vary": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Fri, 02 Nov 2012 10:24:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31480349" + }, + { + "expires": "Sat, 02 Nov 2013 10:32:40 GMT" + }, + { + "content-length": "34963" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Tue, 23 Oct 2012 19:51:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=86400" + }, + { + "expires": "Sun, 04 Nov 2012 03:52:27 GMT" + }, + { + "content-length": "16335" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"4627f-4ccbf4cca7880\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Sat, 17 Nov 2012 13:37:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "content-length": "1140" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-transform, max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Omniture DC/2.0.0" + }, + { + "last-modified": "Mon, 09 Jul 2012 16:00:20 GMT" + }, + { + "etag": "\"115240-38-b5f12d00\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "56" + }, + { + "cache-control": "max-age=7776000" + }, + { + "expires": "Sun, 07 Oct 2012 17:35:44 GMT" + }, + { + "xserver": "www465" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:22 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:25:41 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=31535948" + }, + { + "expires": "Sun, 03 Nov 2013 01:59:43 GMT" + }, + { + "content-length": "41157" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Fri, 12 Oct 2012 15:49:09 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31535796" + }, + { + "expires": "Fri, 01 Nov 2013 04:08:52 GMT" + }, + { + "content-length": "43495" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=63072000" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Mon, 03 Nov 2014 11:29:44 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 11:15:24 GMT" + }, + { + "content-length": "83456" + }, + { + "date": "Sat, 03 Nov 2012 13:37:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:57:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=86400" + }, + { + "expires": "Sun, 04 Nov 2012 11:13:50 GMT" + }, + { + "content-length": "18324" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"8c10d-4cd6f66d2d640\"" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:22 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Tue, 30 Oct 2012 15:44:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=86400" + }, + { + "expires": "Sat, 03 Nov 2012 18:39:25 GMT" + }, + { + "content-length": "24118" + }, + { + "date": "Sat, 03 Nov 2012 13:37:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"bae19-4cd48aa479540\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.22 (Unix) mod_ssl/2.2.22 OpenSSL/0.9.7d" + }, + { + "cache-control": "max-age=86400" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 04 Nov 2012 08:01:50 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 26 Oct 2012 21:25:25 GMT" + }, + { + "content-length": "21999" + }, + { + "date": "Sat, 03 Nov 2012 13:37:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"8cfa9-4ccfcf53bbb40\"" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=86400" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 04 Nov 2012 01:27:36 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 12 Oct 2012 19:32:42 GMT" + }, + { + "content-length": "29003" + }, + { + "date": "Sat, 03 Nov 2012 13:37:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"b3983-4cbe1c0594a80\"" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=86400" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sun, 04 Nov 2012 10:14:22 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:56:52 GMT" + }, + { + "content-length": "28742" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"9b7c0-4cd6f64243100\"" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=31457054" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sat, 02 Nov 2013 12:04:47 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 02 Nov 2012 11:57:38 GMT" + }, + { + "content-length": "24526" + }, + { + "date": "Sat, 03 Nov 2012 13:37:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"3ca55-4cd817fe482c0\"" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "cache-control": "max-age=86400" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Sat, 03 Nov 2012 17:24:54 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Fri, 02 Nov 2012 14:40:40 GMT" + }, + { + "content-length": "45064" + }, + { + "date": "Sat, 03 Nov 2012 13:37:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "etag": "\"fcf54-4cd841e9faa00\"" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Mon, 29 Oct 2012 03:17:34 GMT" + }, + { + "server": "collection8" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\"" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "public, max-age=604800" + }, + { + "date": "Sat, 03 Nov 2012 13:37:23 GMT" + }, + { + "content-length": "5450" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:24 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "173" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "v=848381a268c12381e2d991b8bfad50951e1458d396-6634083950951e14834_3366; expires=Sat, 03-Nov-2012 14:07:24 GMT; path=/; domain=.effectivemeasure.net" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "server": "collection10" + }, + { + "cache-directive": "no-cache" + }, + { + "pragma-directive": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 12 Jul 2011 16:02:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "928" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=27418899" + }, + { + "expires": "Mon, 16 Sep 2013 21:59:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:27 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:26:47 GMT" + }, + { + "cache-control": "max-age=62707765" + }, + { + "expires": "Thu, 30 Oct 2014 08:26:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "content-length": "3417" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:27:16 GMT" + }, + { + "content-length": "2419" + }, + { + "cache-control": "max-age=62707751" + }, + { + "expires": "Thu, 30 Oct 2014 08:26:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:27:16 GMT" + }, + { + "content-length": "1281" + }, + { + "cache-control": "max-age=62707783" + }, + { + "expires": "Thu, 30 Oct 2014 08:27:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:27:28 GMT" + }, + { + "cache-control": "max-age=62707813" + }, + { + "expires": "Thu, 30 Oct 2014 08:27:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "content-length": "56" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 18 Nov 2009 12:17:02 GMT" + }, + { + "content-length": "1275" + }, + { + "cache-control": "max-age=345600" + }, + { + "expires": "Wed, 07 Nov 2012 13:37:29 GMT" + }, + { + "vary": "X-CDN" + }, + { + "access-control-allow-origin": "*" + }, + { + "keep-alive": "timeout=5, max=778" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 12 Oct 2012 09:35:09 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 13:37:29 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css" + }, + { + "content-length": "941" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "private, max-age=0, must-revalidate" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 22 Nov 2011 09:50:32 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1409" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=33813709" + }, + { + "expires": "Fri, 29 Nov 2013 22:19:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 22 Nov 2011 09:39:54 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3436" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=33814374" + }, + { + "expires": "Fri, 29 Nov 2013 22:30:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 22 Nov 2011 09:31:26 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "348" + }, + { + "cache-control": "max-age=33076455" + }, + { + "expires": "Thu, 21 Nov 2013 09:31:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 12 Jul 2012 11:26:22 GMT" + }, + { + "content-length": "3667" + }, + { + "cache-control": "max-age=53347413" + }, + { + "expires": "Mon, 14 Jul 2014 00:21:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 12 Jul 2012 11:26:27 GMT" + }, + { + "content-length": "1999" + }, + { + "cache-control": "max-age=53214541" + }, + { + "expires": "Sat, 12 Jul 2014 11:26:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "301" + }, + { + "server": "Apache" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "location": "http://emp.bbci.co.uk/emp/releases/bump/revisions/905298/embed.js?emp=worldwide&enableClear=1" + }, + { + "content-length": "305" + }, + { + "cache-control": "max-age=211" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:27:21 GMT" + }, + { + "cache-control": "max-age=62707796" + }, + { + "expires": "Thu, 30 Oct 2014 08:27:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "content-length": "303" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:27:37 GMT" + }, + { + "content-length": "4740" + }, + { + "cache-control": "max-age=62707822" + }, + { + "expires": "Thu, 30 Oct 2014 08:27:51 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:37:27 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/html" + }, + { + "content-length": "91216" + }, + { + "date": "Sat, 03 Nov 2012 13:37:27 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "private, max-age=0, must-revalidate" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 09 Oct 2012 17:14:09 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 13:37:29 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "446" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "private, max-age=0, must-revalidate" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 28 Jul 2010 11:07:36 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8432" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=33813771" + }, + { + "expires": "Fri, 29 Nov 2013 22:20:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Mon, 09 Jul 2012 15:09:23 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2234" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "max-age=53344068" + }, + { + "expires": "Sun, 13 Jul 2014 23:25:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 23 Oct 2012 07:38:38 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1657" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "max-age=62100138" + }, + { + "expires": "Thu, 23 Oct 2014 07:39:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:43:33 GMT" + }, + { + "content-length": "5496" + }, + { + "cache-control": "max-age=63033059" + }, + { + "expires": "Mon, 03 Nov 2014 02:48:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/gif" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 03 Nov 2012 11:02:09 GMT" + }, + { + "content-length": "4994" + }, + { + "cache-control": "max-age=63062731" + }, + { + "expires": "Mon, 03 Nov 2014 11:03:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "server": "Apache" + }, + { + "set-cookie": "BGUID=65e0995521ce0199c628d193f15847bbfbb0331236b8ab2579e9db3ae85993f0; expires=Wed, 02-Nov-16 13:37:29 GMT; path=/; domain=bbc.co.uk;" + }, + { + "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "43" + }, + { + "cache-control": "max-age=0, no-cache=Set-Cookie" + }, + { + "expires": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "keep-alive": "timeout=10, max=182" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "application/x-javascript" + }, + { + "location": "http://emp.bbci.co.uk/emp/releases/bump/revisions/905298/embed.js?emp=worldwide&enableClear=1" + }, + { + "content-length": "2628" + }, + { + "cache-control": "max-age=166" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 11 Jul 2012 23:13:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:21:03 GMT" + }, + { + "cache-control": "max-age=63024342" + }, + { + "expires": "Mon, 03 Nov 2014 00:23:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "content-length": "3624" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:21:28 GMT" + }, + { + "content-length": "4643" + }, + { + "cache-control": "max-age=63024320" + }, + { + "expires": "Mon, 03 Nov 2014 00:22:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 09:22:54 GMT" + }, + { + "content-length": "9275" + }, + { + "cache-control": "max-age=62711088" + }, + { + "expires": "Thu, 30 Oct 2014 09:22:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 09:22:55 GMT" + }, + { + "cache-control": "max-age=62711138" + }, + { + "expires": "Thu, 30 Oct 2014 09:23:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "content-length": "11982" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Sat, 03 Nov 2012 11:29:54 GMT" + }, + { + "content-length": "5363" + }, + { + "cache-control": "max-age=63064402" + }, + { + "expires": "Mon, 03 Nov 2014 11:30:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT" + }, + { + "etag": "\"3ff-4cbc5c069d600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 24 Oct 2013 08:22:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1023" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:34:55 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5633" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=63025209" + }, + { + "expires": "Mon, 03 Nov 2014 00:37:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 07 Mar 2012 10:43:47 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7269" + }, + { + "cache-control": "max-age=43235623" + }, + { + "expires": "Tue, 18 Mar 2014 23:31:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:20:54 GMT" + }, + { + "cache-control": "max-age=62707524" + }, + { + "expires": "Thu, 30 Oct 2014 08:22:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:29 GMT" + }, + { + "content-length": "34395" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 30 Oct 2012 09:22:57 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "24217" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=62711138" + }, + { + "expires": "Thu, 30 Oct 2014 09:23:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 31 Oct 2012 15:48:27 GMT" + }, + { + "content-length": "20316" + }, + { + "cache-control": "max-age=63051888" + }, + { + "expires": "Mon, 03 Nov 2014 08:02:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 12 Jul 2011 15:59:09 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "31310" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=27418847" + }, + { + "expires": "Mon, 16 Sep 2013 21:58:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 12 Jul 2011 15:59:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "31708" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=27418799" + }, + { + "expires": "Mon, 16 Sep 2013 21:57:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 12 Jul 2012 10:02:19 GMT" + }, + { + "cache-control": "max-age=53347291" + }, + { + "expires": "Mon, 14 Jul 2014 00:19:05 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:34 GMT" + }, + { + "content-length": "358" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 12 Jul 2011 15:59:09 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5794" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "max-age=27418850" + }, + { + "expires": "Mon, 16 Sep 2013 21:58:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:34 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 12 Jul 2012 10:02:20 GMT" + }, + { + "cache-control": "max-age=53394356" + }, + { + "expires": "Mon, 14 Jul 2014 13:23:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:35 GMT" + }, + { + "content-length": "3759" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 26 Apr 2012 15:23:19 GMT" + }, + { + "etag": "\"453b-4be96914da7c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Tue, 17 Sep 2013 11:52:07 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3403" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:35 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 12 Jul 2012 10:02:24 GMT" + }, + { + "cache-control": "max-age=53487765" + }, + { + "expires": "Tue, 15 Jul 2014 15:20:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:35 GMT" + }, + { + "content-length": "6382" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 30 Oct 2012 09:22:55 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1304" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "max-age=62711132" + }, + { + "expires": "Thu, 30 Oct 2014 09:23:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:37 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:37 GMT" + }, + { + "server": "Apache" + }, + { + "etag": "\"392d4eaba4ddbcf7bb408352be465c19\"" + }, + { + "cache-control": "max-age=1728000, private" + }, + { + "x-lb-nocache": "true" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "286" + }, + { + "keep-alive": "timeout=45" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 09:22:54 GMT" + }, + { + "cache-control": "max-age=62711099" + }, + { + "expires": "Thu, 30 Oct 2014 09:22:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:37 GMT" + }, + { + "content-length": "5788" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "2410" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\"" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Thu, 19 Apr 2012 16:34:19 GMT" + }, + { + "date": "Fri, 02 Nov 2012 23:06:55 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 23:06:55 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "9836" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "52243" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:37 GMT" + }, + { + "server": "Apache" + }, + { + "etag": "\"392d4eaba4ddbcf7bb408352be465c19\"" + }, + { + "cache-control": "private, max-age=30" + }, + { + "x-lb-nocache": "true" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "47" + }, + { + "keep-alive": "timeout=45" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "327" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Mon, 09 Jul 2012 15:09:22 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "970" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "max-age=52968695" + }, + { + "expires": "Wed, 09 Jul 2014 15:09:13 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/png" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 09 Jul 2012 15:09:21 GMT" + }, + { + "content-length": "126" + }, + { + "cache-control": "max-age=52968716" + }, + { + "expires": "Wed, 09 Jul 2014 15:09:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/gif" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:27:16 GMT" + }, + { + "cache-control": "max-age=62707784" + }, + { + "expires": "Thu, 30 Oct 2014 08:27:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "content-length": "3595" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:26:49 GMT" + }, + { + "content-length": "1859" + }, + { + "cache-control": "max-age=62707757" + }, + { + "expires": "Thu, 30 Oct 2014 08:26:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "301" + }, + { + "server": "Apache" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "location": "http://emp.bbci.co.uk/emp/releases/worldwide/revisions/749603_749269_749444_6/embed.js?mediaset=journalism-pc" + }, + { + "content-length": "317" + }, + { + "cache-control": "max-age=160" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 11 Jul 2012 23:13:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 30 Oct 2012 09:22:54 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1014" + }, + { + "cache-control": "max-age=62711082" + }, + { + "expires": "Thu, 30 Oct 2014 09:22:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "application/x-javascript" + }, + { + "location": "http://emp.bbci.co.uk/emp/releases/worldwide/revisions/749603_749269_749444_6/embed.js?mediaset=journalism-pc" + }, + { + "content-length": "6090" + }, + { + "cache-control": "max-age=167" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:26 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:39 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 18 Sep 2012 12:56:25 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT" + }, + { + "etag": "\"adb-4cbc5c069d600\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Thu, 24 Oct 2013 08:21:42 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2779" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-disposition": "attachment" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:40 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1545" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "2506" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:40 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Tue, 15 Feb 2011 16:39:27 GMT" + }, + { + "etag": "\"6414-49c54cec44dc0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Tue, 17 Sep 2013 11:49:13 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7619" + }, + { + "content-type": "application/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:37:39 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Fri, 12 Oct 2012 20:42:56 GMT" + }, + { + "date": "Fri, 02 Nov 2012 15:05:54 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 15:05:54 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "37317" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "81106" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "327" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:40 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 09 Jul 2012 15:09:22 GMT" + }, + { + "cache-control": "max-age=52968720" + }, + { + "expires": "Wed, 09 Jul 2014 15:09:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "content-length": "36830" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "date": "Sat, 03 Nov 2012 13:37:40 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-length": "359" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "530" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:40 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:26:46 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4729" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "max-age=62707754" + }, + { + "expires": "Thu, 30 Oct 2014 08:26:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/png" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:27:33 GMT" + }, + { + "content-length": "130" + }, + { + "cache-control": "max-age=62707807" + }, + { + "expires": "Thu, 30 Oct 2014 08:27:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Nov 2014 13:37:38 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "81990" + }, + { + "date": "Sat, 03 Nov 2012 13:37:38 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "private, max-age=0, must-revalidate" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + }, + { + "last-modified": "Wed, 26 Sep 2012 09:35:41 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "nginx/1.2.0" + }, + { + "date": "Sat, 03 Nov 2012 13:37:43 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "close" + }, + { + "location": "http://ad-emea.doubleclick.net/adj/N2581.122656.2214702362621/B6422491.8;sz=120x30;click0=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/q%3B264679025%3B0-0%3B1%3B49066565%3B47-120/30%3B47423100/47438653/1%3B%3B%7Eokv%3D%3Bslot%3Dpartner_button1%3Bsz%3D120x30%3Bsectn%3Dnews%3Bctype%3Dcontent%3Bnews%3Damerica%3Breferrer%3D%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3D%3Bheadline%3Dromneypromisesus%2527realchang%3B%7Esscs%3D%3f;ord=835861?" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.2.0" + }, + { + "date": "Sat, 03 Nov 2012 13:37:43 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "483" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:44 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Tue, 15 May 2012 22:04:59 GMT" + }, + { + "date": "Fri, 02 Nov 2012 16:00:52 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 16:00:52 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "4146" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "77812" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Fri, 11 Mar 2011 22:15:34 GMT" + }, + { + "date": "Fri, 02 Nov 2012 19:51:36 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 19:51:36 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "3834" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "63968" + }, + { + "cache-control": "public, max-age=86400" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "326" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:44 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "212" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:44 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLuB86QsXkGiDUw6LAw6IpFSRlNUwBT4lFpGQscUZ2EV0HP8; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:37:44 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas06-9" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:37:44 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:44 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "173" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "v=1de6548e4a0d3e45a7c991b8bfad50951e1458d396-6634083950951e28834_3366; expires=Sat, 03-Nov-2012 14:07:44 GMT; path=/; domain=.effectivemeasure.net" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "server": "collection10" + }, + { + "cache-directive": "no-cache" + }, + { + "pragma-directive": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\"" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:37:50 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct=" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-length": "188" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/jpeg" + }, + { + "age": "245581" + }, + { + "date": "Sat, 03 Nov 2012 13:37:45 GMT" + }, + { + "last-modified": "Mon, 14 Nov 2011 18:32:16 GMT" + }, + { + "content-length": "4442" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:50 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct=" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-length": "4449" + }, + { + "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/gif" + }, + { + "age": "73519" + }, + { + "date": "Sat, 03 Nov 2012 13:37:45 GMT" + }, + { + "last-modified": "Fri, 20 Apr 2012 15:50:57 GMT" + }, + { + "content-length": "1709" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/jpeg" + }, + { + "age": "172785" + }, + { + "date": "Sat, 03 Nov 2012 13:37:45 GMT" + }, + { + "last-modified": "Wed, 22 Aug 2012 17:58:48 GMT" + }, + { + "content-length": "4036" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/jpeg" + }, + { + "age": "120980" + }, + { + "date": "Sat, 03 Nov 2012 13:37:45 GMT" + }, + { + "last-modified": "Fri, 02 Dec 2011 21:51:59 GMT" + }, + { + "content-length": "4919" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/gif" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 09 Jul 2012 15:09:22 GMT" + }, + { + "cache-control": "max-age=52968714" + }, + { + "expires": "Wed, 09 Jul 2014 15:09:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:44 GMT" + }, + { + "content-length": "1128" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:44 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 12 Jul 2011 15:59:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "207" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "max-age=27418929" + }, + { + "expires": "Mon, 16 Sep 2013 21:59:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 26 Oct 2012 19:57:24 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "26021" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62403629" + }, + { + "expires": "Sun, 26 Oct 2014 19:58:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:45 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "max-age=300, public, s-maxage=120" + }, + { + "content-type": "application/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:28 GMT" + }, + { + "keep-alive": "timeout=5, max=852" + }, + { + "expires": "Sat, 03 Nov 2012 13:42:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"8550-4c7d8d79b86c0\"" + }, + { + "last-modified": "Wed, 22 Aug 2012 11:14:11 GMT" + }, + { + "content-length": "12181" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 22 Aug 2012 11:14:13 GMT" + }, + { + "etag": "\"31a9-4c7d8d7ba0b40\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=300, public, s-maxage=120" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2364" + }, + { + "content-type": "text/css" + }, + { + "date": "Sat, 03 Nov 2012 13:37:46 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "application/json;charset=UTF-8" + }, + { + "access-control-allow-origin": "*" + }, + { + "access-control-allow-methods": "POST, GET, PUT, OPTIONS" + }, + { + "access-control-allow-headers": "Content-Type, X-Requested-With, *" + }, + { + "content-length": "117" + }, + { + "cache-control": "max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 13:37:47 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "last-modified": "Wed, 22 Aug 2012 11:14:08 GMT" + }, + { + "etag": "\"212e-4c7d8d76dc000\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "expires": "Tue, 17 Sep 2013 11:50:39 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8494" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:37:47 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:57 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\"" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 09 Jul 2012 15:09:23 GMT" + }, + { + "cache-control": "max-age=52968675" + }, + { + "expires": "Wed, 09 Jul 2014 15:09:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:57 GMT" + }, + { + "content-length": "126" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "575" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:58 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "location": "http://mp.apmebf.com/ad/fm/13001-83639-22765-1?mpt=853079&mpvc=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/v%3B264640753%3B0-0%3B0%3B73659506%3B3454-728/90%3B47524155/47539673/1%3B%3B%7Eokv%3D%3Bslot%3Dleaderboard%3Bsz%3D728x90%2C970x66%2C970x90%2C970x250%3Bsectn%3Dnews%3Bctype%3Dcontent%3Bnews%3Dworld%3Breferrer%3Dnewsworlduscanada20104929%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3D%3Bheadline%3Dbombkillspakistanipolitician%3B%7Esscs%3D%3f&host=altfarm.mediaplex.com" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:37:58 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:58 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "43" + }, + { + "cache-control": "max-age=0, no-cache=Set-Cookie" + }, + { + "expires": "Sat, 03 Nov 2012 13:37:58 GMT" + }, + { + "keep-alive": "timeout=10, max=176" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "341" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:58 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-disposition": "attachment" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1387" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 06:50:47 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4705" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=63047620" + }, + { + "expires": "Mon, 03 Nov 2014 06:51:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:58 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + }, + { + "server": "Apache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR PSAo PSDo OUR IND UNI COM NAV\"" + }, + { + "set-cookie": "S=g14vo-413-1351949879145-ya; domain=.apmebf.com; path=/; expires=Mon, 03-Nov-2014 13:37:59 GMT" + }, + { + "location": "http://altfarm.mediaplex.com/ad/fm/13001-83639-22765-1?mpt=853079&mpvc=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/v%3B264640753%3B0-0%3B0%3B73659506%3B3454-728/90%3B47524155/47539673/1%3B%3B%7Eokv%3D%3Bslot%3Dleaderboard%3Bsz%3D728x90%2C970x66%2C970x90%2C970x250%3Bsectn%3Dnews%3Bctype%3Dcontent%3Bnews%3Dworld%3Breferrer%3Dnewsworlduscanada20104929%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3D%3Bheadline%3Dbombkillspakistanipolitician%3B%7Esscs%3D%3f&no_cj_c=1&upsid=545485072431" + }, + { + "content-length": "711" + }, + { + "keep-alive": "timeout=5" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/html; charset=iso-8859-1" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "cache-control": "no-store" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR PSAo PSDo OUR IND UNI COM NAV\"" + }, + { + "set-cookie": "mojo3=13001:22765; expires=Sun, 2-Nov-2014 16:28:10 GMT; path=/; domain=.mediaplex.com;" + }, + { + "location": "http://img.mediaplex.com/content/0/13001/728x90_090512_MVT_Standard.html?mpck=altfarm.mediaplex.com%2Fad%2Fck%2F13001-83639-22765-1%3Fmpt%3D853079&mpt=853079&mpvc=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/v%3B264640753%3B0-0%3B0%3B73659506%3B3454-728/90%3B47524155/47539673/1%3B%3B%7Eokv%3D%3Bslot%3Dleaderboard%3Bsz%3D728x90%2C970x66%2C970x90%2C970x250%3Bsectn%3Dnews%3Bctype%3Dcontent%3Bnews%3Dworld%3Breferrer%3Dnewsworlduscanada20104929%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3D%3Bheadline%3Dbombkillspakistanipolitician%3B%7Esscs%3D%3f" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:37:58 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 09 Oct 2012 13:34:50 GMT" + }, + { + "etag": "\"a5f202-357-4cba066fe7280\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1285" + }, + { + "keep-alive": "timeout=5" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "2518" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "339" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/gif" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 03 Nov 2012 11:26:09 GMT" + }, + { + "cache-control": "max-age=63064269" + }, + { + "expires": "Mon, 03 Nov 2014 11:29:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:58 GMT" + }, + { + "content-length": "18429" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "332" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-length": "332" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "339" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:37:55 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/html" + }, + { + "content-length": "84226" + }, + { + "date": "Sat, 03 Nov 2012 13:37:55 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "private, max-age=0, must-revalidate" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "expires": "Sat Nov 03 13:37:59 UTC 2012" + }, + { + "content-encoding": "gzip" + }, + { + "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "1273" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "212" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:38:05 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct=" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-length": "188" + }, + { + "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLuB86QsXkGiDUw6LAw6IpFSRlNUwBT4lNpFQ0QUg4OfFcQQ1VXgXlFGVpIpliI6eB4eKxBjZB19azY=; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:38:00 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas01-1" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "expires": "Sat Nov 03 13:37:59 UTC 2012" + }, + { + "content-encoding": "gzip" + }, + { + "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "content-type": "text/html" + }, + { + "content-length": "7375" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:05 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct=" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-length": "4449" + }, + { + "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "56812" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 12:45:03 GMT" + }, + { + "server": "Apache/2.2.3 (CentOS)" + }, + { + "last-modified": "Sat, 18 Aug 2012 06:04:35 GMT" + }, + { + "etag": "\"5d0aba4-ddec-4c7840d06c2c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=3600" + }, + { + "expires": "Sat, 03 Nov 2012 13:45:03 GMT" + }, + { + "x-permitted-cross-domain-policies": "all" + }, + { + "age": "3177" + }, + { + "x-amz-cf-id": "Nqvl7hdh1ZID-spjM3MSj_rmvJrOblt2qYh9QKaP4AUq-J79-UBaKg==" + }, + { + "via": "1.0 f9710778d388f0645feb35b6ec48d316.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:00 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "173" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "v=51bfcbb530581eaf84e991b8bfad50951e1458d396-6634083950951e38834_3366; expires=Sat, 03-Nov-2012 14:08:00 GMT; path=/; domain=.effectivemeasure.net" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "server": "collection10" + }, + { + "cache-directive": "no-cache" + }, + { + "pragma-directive": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\"" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:37:59 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "application/json;charset=UTF-8" + }, + { + "access-control-allow-origin": "*" + }, + { + "access-control-allow-methods": "POST, GET, PUT, OPTIONS" + }, + { + "access-control-allow-headers": "Content-Type, X-Requested-With, *" + }, + { + "content-length": "111" + }, + { + "cache-control": "max-age=31" + }, + { + "date": "Sat, 03 Nov 2012 13:38:00 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:27:19 GMT" + }, + { + "cache-control": "max-age=62707764" + }, + { + "expires": "Thu, 30 Oct 2014 08:27:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:06 GMT" + }, + { + "content-length": "297" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:06 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "43" + }, + { + "cache-control": "max-age=0, no-cache=Set-Cookie" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:06 GMT" + }, + { + "keep-alive": "timeout=10, max=162" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 12 Jul 2012 10:02:19 GMT" + }, + { + "cache-control": "max-age=53487737" + }, + { + "expires": "Tue, 15 Jul 2014 15:20:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "content-length": "7969" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 16:22:37 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4852" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62995766" + }, + { + "expires": "Sun, 02 Nov 2014 16:27:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 23:13:05 GMT" + }, + { + "content-length": "6548" + }, + { + "cache-control": "max-age=63020343" + }, + { + "expires": "Sun, 02 Nov 2014 23:17:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 01 Nov 2012 08:04:19 GMT" + }, + { + "cache-control": "max-age=62880339" + }, + { + "expires": "Sat, 01 Nov 2014 08:23:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "content-length": "4144" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 01 Nov 2012 14:00:52 GMT" + }, + { + "content-length": "3761" + }, + { + "cache-control": "max-age=62901025" + }, + { + "expires": "Sat, 01 Nov 2014 14:08:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Thu, 01 Nov 2012 18:22:05 GMT" + }, + { + "content-length": "6600" + }, + { + "cache-control": "max-age=62916820" + }, + { + "expires": "Sat, 01 Nov 2014 18:31:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "454" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 14:39:26 GMT" + }, + { + "content-length": "6851" + }, + { + "cache-control": "max-age=62989321" + }, + { + "expires": "Sun, 02 Nov 2014 14:40:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 25 Oct 2012 11:27:56 GMT" + }, + { + "content-length": "5411" + }, + { + "cache-control": "max-age=62320782" + }, + { + "expires": "Sat, 25 Oct 2014 20:57:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "location": "http://img.mediaplex.com/content/0/18916/LT_XML_RateTable_ScrollingHeadline_PurpleArrows_RecordLows_728x90_050112.js?mpck=altfarm.mediaplex.com%2Fad%2Fck%2F18916-133472-32866-8%3Fmpt%3D862767&mpt=862767&mpvc=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/o%3B264441578%3B0-0%3B0%3B19196826%3B3454-728/90%3B49903581/49895429/1%3B%3B%7Eokv%3D%3Bslot%3Dleaderboard%3Bsz%3D728x90%2C970x66%2C970x90%2C970x250%3Bsectn%3Dnews%3Bctype%3Dindex%3Bnews%3Dworld%3Breferrer%3Dnewsworldasia20190337%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3DJ08781_10132%3Brsi%3DJ08781_10628%3B%7Esscs%3D%3f" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "cache-control": "no-store" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR PSAo PSDo OUR IND UNI COM NAV\"" + }, + { + "set-cookie": "mojo3=18916:32866/13001:22765; expires=Sun, 2-Nov-2014 16:53:09 GMT; path=/; domain=.mediaplex.com;" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\"" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 01 May 2012 19:15:40 GMT" + }, + { + "etag": "\"2119c1-1526-4befe65754f00\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "6980" + }, + { + "keep-alive": "timeout=5" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:05 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/html" + }, + { + "content-length": "90666" + }, + { + "date": "Sat, 03 Nov 2012 13:38:05 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "private, max-age=0, must-revalidate" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 19 Oct 2011 07:28:39 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "18359" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=52349338" + }, + { + "expires": "Wed, 02 Jul 2014 11:07:05 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 18:19:24 GMT" + }, + { + "cache-control": "max-age=63002534" + }, + { + "expires": "Sun, 02 Nov 2014 18:20:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "content-length": "5791" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 09:30:47 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5035" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=63057300" + }, + { + "expires": "Mon, 03 Nov 2014 09:33:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 06:55:42 GMT" + }, + { + "cache-control": "max-age=62961571" + }, + { + "expires": "Sun, 02 Nov 2014 06:57:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "content-length": "6266" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Wed, 31 Oct 2012 15:53:37 GMT" + }, + { + "content-length": "4757" + }, + { + "cache-control": "max-age=62820986" + }, + { + "expires": "Fri, 31 Oct 2014 15:54:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 01 Nov 2012 09:01:42 GMT" + }, + { + "cache-control": "max-age=62882710" + }, + { + "expires": "Sat, 01 Nov 2014 09:03:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "content-length": "5396" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:09:30 GMT" + }, + { + "content-length": "4759" + }, + { + "cache-control": "max-age=62965934" + }, + { + "expires": "Sun, 02 Nov 2014 08:10:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:24:17 GMT" + }, + { + "content-length": "3202" + }, + { + "cache-control": "max-age=62989607" + }, + { + "expires": "Sun, 02 Nov 2014 14:44:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:01:25 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4022" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62983627" + }, + { + "expires": "Sun, 02 Nov 2014 13:05:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 08:54:55 GMT" + }, + { + "cache-control": "max-age=62970180" + }, + { + "expires": "Sun, 02 Nov 2014 09:21:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:08 GMT" + }, + { + "content-length": "4853" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 01 Nov 2012 13:44:04 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3289" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "max-age=62901702" + }, + { + "expires": "Sat, 01 Nov 2014 14:19:50 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:08 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 01 Nov 2012 16:55:01 GMT" + }, + { + "content-length": "7105" + }, + { + "cache-control": "max-age=62911093" + }, + { + "expires": "Sat, 01 Nov 2014 16:56:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 14 Sep 2012 07:57:36 GMT" + }, + { + "cache-control": "max-age=58732357" + }, + { + "expires": "Sun, 14 Sep 2014 08:10:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:08 GMT" + }, + { + "content-length": "3960" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Tue, 21 Aug 2012 07:36:37 GMT" + }, + { + "content-length": "3948" + }, + { + "cache-control": "max-age=56656721" + }, + { + "expires": "Thu, 21 Aug 2014 07:36:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 09 Mar 2006 21:32:31 GMT" + }, + { + "etag": "\"9f40d-3a-40e969d2259c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:08 GMT" + }, + { + "content-length": "63" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Mon, 05 Mar 2012 12:15:23 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "59958" + }, + { + "cache-control": "max-age=42071869" + }, + { + "expires": "Wed, 05 Mar 2014 12:15:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "text/javascript" + }, + { + "pragma": "" + }, + { + "content-length": "479" + }, + { + "cache-control": "max-age=30" + }, + { + "date": "Sat, 03 Nov 2012 13:38:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "2493" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "321" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-length": "363" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "212" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:38:14 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct=" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-length": "188" + }, + { + "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:14 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct=" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "-1" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-length": "4449" + }, + { + "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-disposition": "attachment" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1396" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLuBg59Xwl/EEO1FURBA3cAlgmns+ZjtUnj+OABraDN8bCZzDmjhJGhbKAxEWBcNLyPWU8lPaSzTe300; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:38:09 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas04-1" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "173" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "v=d12d53fe4bd39099b1d991b8bfad50951e1458d396-6634083950951e41834_3366; expires=Sat, 03-Nov-2012 14:08:09 GMT; path=/; domain=.effectivemeasure.net" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "server": "collection10" + }, + { + "cache-directive": "no-cache" + }, + { + "pragma-directive": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/gif" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 09 Jul 2012 15:09:21 GMT" + }, + { + "cache-control": "max-age=52968683" + }, + { + "expires": "Wed, 09 Jul 2014 15:09:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + }, + { + "content-length": "11937" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:26:43 GMT" + }, + { + "content-type": "image/png" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1594" + }, + { + "cache-control": "max-age=62707699" + }, + { + "expires": "Thu, 30 Oct 2014 08:26:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Mon, 16 Jul 2012 20:54:14 GMT" + }, + { + "etag": "\"6d6c23-816c-4c4f8a1e64980\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "33132" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:38:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\"" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "317" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "1222" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-type": "text/html" + }, + { + "content-length": "4631" + }, + { + "set-cookie": "PRpc=|HrYvHDG1:1|#;domain=ads.pointroll.com; path=/; expires=Mon, 03-Nov-2014 13:38:23 GMT;" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 12:33:21 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "17839" + }, + { + "cache-control": "max-age=62987851" + }, + { + "expires": "Sun, 02 Nov 2014 14:15:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:51:54 GMT" + }, + { + "cache-control": "max-age=62946923" + }, + { + "expires": "Sun, 02 Nov 2014 02:53:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "content-length": "4827" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 15:48:41 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5891" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62993480" + }, + { + "expires": "Sun, 02 Nov 2014 15:49:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 10:44:04 GMT" + }, + { + "content-length": "3664" + }, + { + "cache-control": "max-age=62975317" + }, + { + "expires": "Sun, 02 Nov 2014 10:46:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 31 Oct 2012 13:08:31 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5589" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62813487" + }, + { + "expires": "Fri, 31 Oct 2014 13:49:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 31 Oct 2012 11:47:26 GMT" + }, + { + "content-length": "6787" + }, + { + "cache-control": "max-age=62806355" + }, + { + "expires": "Fri, 31 Oct 2014 11:50:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "43" + }, + { + "cache-control": "max-age=0, no-cache=Set-Cookie" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "keep-alive": "timeout=10, max=150" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "server": "Apache" + }, + { + "cache-control": "private, max-age=30" + }, + { + "x-lb-nocache": "true" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "47" + }, + { + "keep-alive": "timeout=45" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "1232" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-type": "text/html" + }, + { + "content-length": "4657" + }, + { + "set-cookie": "PRpc=|HrYwHDG0:1|HrYvHDG1:1|#;domain=ads.pointroll.com; path=/; expires=Mon, 03-Nov-2014 13:38:23 GMT;" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 25 Oct 2012 12:54:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6289" + }, + { + "cache-control": "max-age=62291861" + }, + { + "expires": "Sat, 25 Oct 2014 12:56:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 01 Nov 2012 05:59:50 GMT" + }, + { + "cache-control": "max-age=62871966" + }, + { + "expires": "Sat, 01 Nov 2014 06:04:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "content-length": "4071" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 01 Nov 2012 09:39:39 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6862" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62885045" + }, + { + "expires": "Sat, 01 Nov 2014 09:42:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Mon, 24 Sep 2012 12:45:46 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4014" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=59612845" + }, + { + "expires": "Wed, 24 Sep 2014 12:45:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "360" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 05:12:35 GMT" + }, + { + "content-length": "6772" + }, + { + "cache-control": "max-age=62955857" + }, + { + "expires": "Sun, 02 Nov 2014 05:22:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-length": "548" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "545" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "545" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Tue, 01 Feb 2011 16:45:17 GMT" + }, + { + "date": "Fri, 02 Nov 2012 19:49:21 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 19:49:21 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "4447" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "64143" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Tue, 25 Sep 2012 20:37:11 GMT" + }, + { + "date": "Fri, 02 Nov 2012 20:14:54 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 20:14:54 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "2993" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "62610" + }, + { + "cache-control": "public, max-age=86400" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:21 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/html" + }, + { + "content-length": "103860" + }, + { + "date": "Sat, 03 Nov 2012 13:38:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "private, max-age=0, must-revalidate" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Mon, 22 Oct 2012 18:53:42 GMT" + }, + { + "date": "Fri, 02 Nov 2012 21:59:32 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 21:59:32 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "5619" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "56332" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Mon, 22 Oct 2012 18:54:38 GMT" + }, + { + "date": "Fri, 02 Nov 2012 21:59:33 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 21:59:33 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "5379" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "56331" + }, + { + "cache-control": "public, max-age=86400" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "GFE/2.0" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "content-length": "0" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "GFE/2.0" + }, + { + "content-length": "0" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "content-encoding": "gzip" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Fri, 05 Nov 2010 18:11:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 08:14:05 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 08:14:05 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "43" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "19459" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-type": "text/plain" + }, + { + "content-length": "3528" + }, + { + "cache-control": "private, max-age=506694" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-disposition": "attachment" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "882" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 07:32:16 GMT" + }, + { + "cache-control": "max-age=62963730" + }, + { + "expires": "Sun, 02 Nov 2014 07:33:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "content-length": "6112" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:53:00 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6904" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62947059" + }, + { + "expires": "Sun, 02 Nov 2014 02:56:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 29 Oct 2012 23:54:38 GMT" + }, + { + "content-length": "6467" + }, + { + "cache-control": "max-age=62677369" + }, + { + "expires": "Thu, 30 Oct 2014 00:01:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 01:56:44 GMT" + }, + { + "content-length": "5790" + }, + { + "cache-control": "max-age=62943937" + }, + { + "expires": "Sun, 02 Nov 2014 02:04:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Thu, 15 Dec 2011 11:42:59 GMT" + }, + { + "content-length": "13166" + }, + { + "cache-control": "max-age=60312573" + }, + { + "expires": "Thu, 02 Oct 2014 15:07:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:47:01 GMT" + }, + { + "content-length": "6715" + }, + { + "cache-control": "max-age=63007794" + }, + { + "expires": "Sun, 02 Nov 2014 19:48:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "42" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Sun, 05-Jun-2005 22:00:00 GMT" + }, + { + "set-cookie": "u2=0c1d5772-7a75-4913-9e34-91b1ec36e6763Qv0b0; expires=Fri, 01-Feb-2013 09:38:24 GMT; domain=.serving-sys.com; path=/" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"NOI DEVa OUR BUS UNI\"" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "2370" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Nov 2014 13:38:24 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "17960" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "Keep-Alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "max-age=63072000" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + }, + { + "last-modified": "Mon, 08 Nov 2010 14:53:56 GMT" + }, + { + "keep-alive": "timeout=5, max=713" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 24 May 2012 20:52:06 GMT" + }, + { + "date": "Fri, 02 Nov 2012 20:45:30 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 20:45:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "18377" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "60774" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLuBg59Xwl/EEO1FURBA3cAlgmns+ZhxgFZ2Xd28p4N8+qai9qH+vXEtJkM6N3AzKCRseBomFyz6/H0m; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:38:24 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas09-1" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Mon, 08 Nov 2010 14:53:48 GMT" + }, + { + "content-length": "17610" + }, + { + "cache-control": "max-age=63072000" + }, + { + "expires": "Mon, 03 Nov 2014 13:38:23 GMT" + }, + { + "vary": "X-CDN" + }, + { + "access-control-allow-origin": "*" + }, + { + "keep-alive": "timeout=5, max=793" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "server": "Omniture DC/2.0.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "set-cookie": "s_vi=[CS]v1|284A8F0905160D8B-600001A1C0108CD4[CE]; Expires=Thu, 2 Nov 2017 13:38:24 GMT; Domain=sa.bbc.com; Path=/" + }, + { + "x-c": "ms-4.4.9" + }, + { + "expires": "Fri, 02 Nov 2012 13:38:24 GMT" + }, + { + "last-modified": "Sun, 04 Nov 2012 13:38:24 GMT" + }, + { + "cache-control": "no-cache, no-store, max-age=0, no-transform, private" + }, + { + "pragma": "no-cache" + }, + { + "etag": "\"50951E50-1A84-669E56BC\"" + }, + { + "vary": "*" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA OUR IND COM NAV STA\"" + }, + { + "xserver": "www665" + }, + { + "content-length": "43" + }, + { + "keep-alive": "timeout=15" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 00:08:06 GMT" + }, + { + "cache-control": "max-age=62937399" + }, + { + "expires": "Sun, 02 Nov 2014 00:15:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "content-length": "7180" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 31 Oct 2012 15:54:41 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4902" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62848278" + }, + { + "expires": "Fri, 31 Oct 2014 23:29:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 01 Nov 2012 23:33:51 GMT" + }, + { + "content-length": "3930" + }, + { + "cache-control": "max-age=62935245" + }, + { + "expires": "Sat, 01 Nov 2014 23:39:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "173" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "v=72911efde47ed7df994991b8bfad50951e1458d396-6634083950951e50834_3366; expires=Sat, 03-Nov-2012 14:08:24 GMT; path=/; domain=.effectivemeasure.net" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "server": "collection10" + }, + { + "cache-directive": "no-cache" + }, + { + "pragma-directive": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Wed, 31 Oct 2012 23:02:53 GMT" + }, + { + "content-length": "3589" + }, + { + "cache-control": "max-age=62846973" + }, + { + "expires": "Fri, 31 Oct 2014 23:07:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-type": "text/plain" + }, + { + "content-length": "15586" + }, + { + "cache-control": "private, max-age=506675" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "20151" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 25 Oct 2012 17:13:44 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0544416d4b2cd1:b56\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 05 Mar 2012 12:20:37 GMT" + }, + { + "cache-control": "max-age=42072135" + }, + { + "expires": "Wed, 05 Mar 2014 12:20:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:22 GMT" + }, + { + "content-length": "59958" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 08:26:48 GMT" + }, + { + "cache-control": "max-age=62707710" + }, + { + "expires": "Thu, 30 Oct 2014 08:26:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "content-length": "189" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 26 Oct 2012 15:18:41 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5471" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62387032" + }, + { + "expires": "Sun, 26 Oct 2014 15:22:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-pad": "avoid browser bug" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 15 Nov 2011 09:49:33 GMT" + }, + { + "content-length": "3645" + }, + { + "cache-control": "max-age=59275525" + }, + { + "expires": "Sat, 20 Sep 2014 15:03:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 01:30:29 GMT" + }, + { + "x-pad": "avoid browser bug" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5937" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "max-age=62942201" + }, + { + "expires": "Sun, 02 Nov 2014 01:35:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 17:42:14 GMT" + }, + { + "cache-control": "max-age=63000297" + }, + { + "expires": "Sun, 02 Nov 2014 17:43:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "content-length": "6807" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "x-pad": "avoid browser bug" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 31 Oct 2012 23:03:40 GMT" + }, + { + "content-length": "4382" + }, + { + "cache-control": "max-age=62846946" + }, + { + "expires": "Fri, 31 Oct 2014 23:07:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 30 Oct 2012 23:49:59 GMT" + }, + { + "content-length": "5299" + }, + { + "cache-control": "max-age=62768266" + }, + { + "expires": "Fri, 31 Oct 2014 01:16:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:24 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:38:26 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:38:26 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "29965" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 25 Oct 2012 17:12:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"02d8becd3b2cd1:b56\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "date": "Sat, 03 Nov 2012 13:38:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:38:31 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:31 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\"" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:31 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "43" + }, + { + "cache-control": "max-age=0, no-cache=Set-Cookie" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:31 GMT" + }, + { + "keep-alive": "timeout=10, max=91" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "312" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:32 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "1216" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:32 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:38:32 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-type": "text/html" + }, + { + "content-length": "4631" + }, + { + "set-cookie": "PRpc=|HrYwHDG0:1|HrYvHDG1:2|#;domain=ads.pointroll.com; path=/; expires=Mon, 03-Nov-2014 13:38:32 GMT;" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "322" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 20 Jul 2012 11:50:26 GMT" + }, + { + "cache-control": "max-age=53907180" + }, + { + "expires": "Sun, 20 Jul 2014 11:51:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:32 GMT" + }, + { + "content-length": "2149" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-disposition": "attachment" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1660" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "609" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-msadid": "291301914" + }, + { + "date": "Sat, 03 Nov 2012 13:38:32 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "2882" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "320" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "50" + }, + { + "allow": "GET" + }, + { + "expires": "Tue, 06 Nov 2012 10:23:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "nginx/0.8.54" + }, + { + "date": "Sat, 03 Nov 2012 13:38:26 GMT" + }, + { + "content-type": "application/xml" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + }, + { + "set-cookie": "pixel_f52666608=1; Domain=.dimestore.com; Expires=Sun, 03-Nov-2013 13:38:26 GMT" + }, + { + "location": "http://content.dimestore.com/pixel.gif" + }, + { + "content-length": "0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:30 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/html" + }, + { + "content-length": "91710" + }, + { + "date": "Sat, 03 Nov 2012 13:38:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cache-action": "MISS" + }, + { + "x-cache-age": "0" + }, + { + "cache-control": "private, max-age=0, must-revalidate" + }, + { + "x-lb-nocache": "true" + }, + { + "vary": "X-CDN" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "538" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "356" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "539" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-length": "545" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "content-encoding": "gzip" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:38:34 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "GFE/2.0" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "content-length": "0" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "321" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:34 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "GFE/2.0" + }, + { + "content-length": "0" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "content-encoding": "gzip" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "18600" + }, + { + "allow": "GET" + }, + { + "expires": "Sun, 04 Nov 2012 07:03:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:34 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "42" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Sun, 05-Jun-2005 22:00:00 GMT" + }, + { + "set-cookie": "u2=0c1d5772-7a75-4913-9e34-91b1ec36e6763Qv0bg; expires=Fri, 01-Feb-2013 09:38:34 GMT; domain=.serving-sys.com; path=/" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"NOI DEVa OUR BUS UNI\"" + }, + { + "date": "Sat, 03 Nov 2012 13:38:33 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "245" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:34 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.6.35" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "49" + }, + { + "last-modified": "Fri, 05 Aug 2011 18:45:32 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 13:38:34 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:35 GMT" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 19 Sep 2012 23:30:39 GMT" + }, + { + "etag": "\"bed15b-d00-4ca1664f965c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "3328" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:38:35 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:38:37 GMT" + }, + { + "content-type": "application/x-javascript" + }, + { + "connection": "close" + }, + { + "set-cookie": "BMX_3PC=1; path=/; domain=.voicefive.com;" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI COR NID CUR DEV TAI PSA IVA OUR STA UNI NAV INT\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "vary": "User-Agent,Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8240" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "content-type": "text/javascript" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:37 GMT" + }, + { + "cache-control": "max-age=0, no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "date": "Sat, 03 Nov 2012 13:38:37 GMT" + }, + { + "content-length": "392" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "CMDD=AAIWeQE*;domain=casalemedia.com;path=/;expires=Sun, 04 Nov 2012 13:38:37 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLuBg59Xwl/EEO1FURBA3cAlgmns+bAxJsyTL2hw/WD8n92ZW/I4JwcH7E4ANXFCKgXlxsjUzY2F7dfMxN21mUJt+5Zxhw==; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:38:37 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas02-1" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:38:37 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:37 GMT" + }, + { + "server": "Omniture DC/2.0.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "set-cookie": "s_vi=[CS]v1|284A8F0905160D8B-600001A1C0108CD4[CE]; Expires=Thu, 2 Nov 2017 13:38:37 GMT; Domain=sa.bbc.com; Path=/" + }, + { + "x-c": "ms-4.4.9" + }, + { + "expires": "Fri, 02 Nov 2012 13:38:37 GMT" + }, + { + "last-modified": "Sun, 04 Nov 2012 13:38:37 GMT" + }, + { + "cache-control": "no-cache, no-store, max-age=0, no-transform, private" + }, + { + "pragma": "no-cache" + }, + { + "etag": "\"50951E5D-2288-2D7FF956\"" + }, + { + "vary": "*" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA OUR IND COM NAV STA\"" + }, + { + "xserver": "www381" + }, + { + "content-length": "43" + }, + { + "keep-alive": "timeout=15" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:38:37 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "content-length": "173" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "v=b90bb042855f902565c991b8bfad50951e1458d396-6634083950951e5d834_3366; expires=Sat, 03-Nov-2012 14:08:37 GMT; path=/; domain=.effectivemeasure.net" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "server": "collection10" + }, + { + "cache-directive": "no-cache" + }, + { + "pragma-directive": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\"" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:38:37 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache/2.2.19 (Unix)" + }, + { + "content-type": "application/json;charset=UTF-8" + }, + { + "access-control-allow-origin": "*" + }, + { + "access-control-allow-methods": "POST, GET, PUT, OPTIONS" + }, + { + "access-control-allow-headers": "Content-Type, X-Requested-With, *" + }, + { + "content-length": "112" + }, + { + "cache-control": "max-age=17" + }, + { + "date": "Sat, 03 Nov 2012 13:38:37 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 24 Jun 2005 22:51:33 GMT" + }, + { + "etag": "\"fec19c-1b-3fa51a4b8c740\"" + }, + { + "accept-ranges": "bytes" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "38" + }, + { + "date": "Sat, 03 Nov 2012 13:38:37 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Mon, 22 Oct 2012 15:55:36 GMT" + }, + { + "etag": "\"4016f-8a-4cca7e25a0e00\"" + }, + { + "accept-ranges": "bytes" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "135" + }, + { + "date": "Sat, 03 Nov 2012 13:38:38 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "273" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:38:38 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:38:38 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:38:41 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_24.json b/jetty-http2/http2-hpack/src/test/resources/data/story_24.json new file mode 100644 index 00000000000..c2948956c05 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_24.json @@ -0,0 +1,1187 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "302" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "connection": "close" + }, + { + "location": "http://www.craigslist.org/about/sites/" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:34:16 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=14400" + }, + { + "last-modified": "Sat, 03 Nov 2012 10:03:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 10:03:45 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "10344" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 10:03:45 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Tue, 16 Oct 2012 22:03:00 GMT" + }, + { + "date": "Tue, 16 Oct 2012 22:03:00 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "1099" + }, + { + "content-type": "text/css; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 15 Nov 2012 22:03:00 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=15, public" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:33:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:33:59 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "6344" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:34:14 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Tue, 09 Oct 2012 06:13:28 GMT" + }, + { + "date": "Tue, 09 Oct 2012 06:13:28 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "28017" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 08 Nov 2012 06:13:28 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "last-modified": "Mon, 23 Jun 2008 23:06:11 GMT" + }, + { + "cache-control": "public, max-age=315360000" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Tue, 09 Oct 2012 05:33:00 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "1150" + }, + { + "content-type": "text/plain" + }, + { + "server": "Apache" + }, + { + "expires": "Fri, 07 Oct 2022 05:33:00 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=3600, public" + }, + { + "last-modified": "Sat, 03 Nov 2012 12:36:54 GMT" + }, + { + "set-cookie": "cl_def_hp=shoals; domain=.craigslist.org; path=/; expires=Sun, 03-Nov-13 12:36:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:36:54 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "6245" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:36:54 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:53:37 GMT" + }, + { + "date": "Thu, 01 Nov 2012 20:53:37 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "6047" + }, + { + "content-type": "text/css; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Dec 2012 20:53:37 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:53:17 GMT" + }, + { + "date": "Thu, 01 Nov 2012 20:53:17 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "6344" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Dec 2012 20:53:17 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Tue, 09 Oct 2012 06:01:51 GMT" + }, + { + "date": "Tue, 09 Oct 2012 06:01:51 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "473" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 08 Nov 2012 06:01:51 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Tue, 09 Oct 2012 06:01:55 GMT" + }, + { + "date": "Tue, 09 Oct 2012 06:01:55 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "28017" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 08 Nov 2012 06:01:55 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "last-modified": "Mon, 23 Jun 2008 23:06:11 GMT" + }, + { + "cache-control": "public, max-age=315360000" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Tue, 09 Oct 2012 05:33:00 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "1150" + }, + { + "content-type": "text/plain" + }, + { + "server": "Apache" + }, + { + "expires": "Fri, 07 Oct 2022 05:33:00 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=600" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:34:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:34:21 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "9660" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:49:21 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Tue, 09 Oct 2012 06:21:38 GMT" + }, + { + "date": "Tue, 09 Oct 2012 06:21:38 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "225" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 08 Nov 2012 06:21:38 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Tue, 09 Oct 2012 07:20:18 GMT" + }, + { + "date": "Tue, 09 Oct 2012 07:20:18 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "2857" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 08 Nov 2012 07:20:18 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Tue, 30 Oct 2012 21:50:50 GMT" + }, + { + "date": "Tue, 30 Oct 2012 21:50:50 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "1398" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 29 Nov 2012 21:50:50 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Thu, 01 Nov 2012 21:26:48 GMT" + }, + { + "date": "Thu, 01 Nov 2012 21:26:48 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "40353" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 01 Dec 2012 21:26:48 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Fri, 02 Nov 2012 21:46:27 GMT" + }, + { + "date": "Fri, 02 Nov 2012 21:46:27 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "2458" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Sun, 02 Dec 2012 21:46:27 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Mon, 15 Oct 2012 22:07:17 GMT" + }, + { + "date": "Mon, 15 Oct 2012 22:07:17 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "727" + }, + { + "content-type": "text/javascript; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Wed, 14 Nov 2012 22:07:17 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=2592000" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Fri, 02 Nov 2012 21:46:28 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=2592000" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Fri, 02 Nov 2012 21:46:27 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=2592000" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Fri, 02 Nov 2012 21:46:28 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=2592000" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Fri, 02 Nov 2012 21:46:27 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=600" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:34:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:34:17 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "10780" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Sat, 03 Nov 2012 13:49:18 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:17:50 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:17:50 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "2245" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 13:17:50 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=2592000" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Mon, 22 Oct 2012 22:00:11 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=2592000" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 27 Oct 2012 12:09:05 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=2592000" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 27 Oct 2012 07:36:12 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=2592000" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Mon, 22 Oct 2012 22:00:12 GMT" + }, + { + "server": "Apache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=14400" + }, + { + "last-modified": "Sat, 03 Nov 2012 12:53:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:53:23 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "5733" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 12:53:23 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=14400" + }, + { + "last-modified": "Sat, 03 Nov 2012 10:58:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 10:58:55 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "1480" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 10:58:55 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "public, max-age=14400" + }, + { + "last-modified": "Sat, 03 Nov 2012 09:53:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 09:53:38 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "10400" + }, + { + "content-type": "text/html; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Mon, 03 Dec 2012 09:53:38 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "max-age=2592000, public" + }, + { + "last-modified": "Tue, 09 Oct 2012 06:01:47 GMT" + }, + { + "date": "Tue, 09 Oct 2012 06:01:47 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "4861" + }, + { + "content-type": "text/css; charset=iso-8859-1" + }, + { + "x-frame-options": "Allow-From https://forums.craigslist.org" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 08 Nov 2012 06:01:47 GMT" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_25.json b/jetty-http2/http2-hpack/src/test/resources/data/story_25.json new file mode 100644 index 00000000000..a97403849b4 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_25.json @@ -0,0 +1,8637 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "301" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "etag": "" + }, + { + "last-modified": "Sat, 3 Nov 2012 13:18:25 GMT" + }, + { + "location": "http://www.ebay.com" + }, + { + "rlogid": "p4fug%60fvehq%60%3C%3Dsm%2Bpu56*a37%3Fb0%60-13ac6788085" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:31:56 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "nonsession=CgAFMABhSdlBNNTA5NTFjY2QuMC4xLjEuMTQ5LjMuMC4xAMoAIFn7Hk1jNjc4ODNmMTEzYTBhNTY5NjRlNjQ2YzZmZmFhMWFjMQDLAAFQlSPVMX8u5Z8*; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:31:57 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "14114" + }, + { + "date": "Sat, 03 Nov 2012 13:31:56 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 02 Nov 2012 00:07:22 GMT" + }, + { + "etag": "\"558014-cc3-4cd77eb75a280\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "3267" + }, + { + "x-cnection": "close" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4n%60rujfudlwc%3D9vt*ts67.g15ea31-13ac67885c6-0x1a1" + }, + { + "set-cookie": "npii=bcguid/c67885c613a0a0a9f6568b16ff5917ee5276504e^tguid/c67883f113a0a56964e646c6ffaa1ac15276504e^; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:31:58 GMT; Path=/" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa ADMa DEVa PSDo PSAa OUR SAMo IND UNI COM NAV INT STA DEM PRE\"" + }, + { + "cache-control": "private, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "42" + }, + { + "date": "Sat, 03 Nov 2012 13:31:57 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 15:31:45 GMT" + }, + { + "last-modified": "Sat, 16 Aug 2003 20:42:27 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "49" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "last-modified": "Thu, 18 Oct 2012 23:53:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80183dd68badcd1:720\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "2539" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "expires": "Mon, 10 Dec 2012 22:14:50 GMT" + }, + { + "last-modified": "Tue, 10 Jul 2012 00:18:56 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "219" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "last-modified": "Tue, 10 Jul 2012 00:17:53 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"808e7072315ecd1:5f1\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "201" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "last-modified": "Wed, 18 Jul 2012 20:33:33 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "1623" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9vl*th%7Fbad%7F72%3D-13ac6788850-0x16f" + }, + { + "cache-control": "private, max-age=86400" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9ve*t%28747%60e%7E6-13ac678862e-0xfb" + }, + { + "cache-control": "private, max-age=86400" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:31:57 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9ve*t%28747%60e%7Eb-13ac6788670-0x141" + }, + { + "cache-control": "private, max-age=86400" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:31:57 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07p-13a4b38c06e-0x161" + }, + { + "last-modified": "Tue, 09 Oct 2012 23:50:57 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "4212" + }, + { + "cache-control": "max-age=29468235" + }, + { + "expires": "Thu, 10 Oct 2013 15:09:13 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07%3B-13a65e7cdbc-0x16b" + }, + { + "last-modified": "Mon, 15 Oct 2012 19:11:16 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "5662" + }, + { + "cache-control": "max-age=29915920" + }, + { + "expires": "Tue, 15 Oct 2013 19:30:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07m-13abdd493d5-0x16d" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:39:43 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "9184" + }, + { + "cache-control": "max-age=31391044" + }, + { + "expires": "Fri, 01 Nov 2013 21:16:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 31 Jan 2012 02:58:34 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "3282" + }, + { + "cache-control": "max-age=23333195" + }, + { + "expires": "Wed, 31 Jul 2013 14:58:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 06 Sep 2012 16:51:31 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "5440" + }, + { + "cache-control": "max-age=26536771" + }, + { + "expires": "Fri, 06 Sep 2013 16:51:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 11 Oct 2012 19:15:19 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5148" + }, + { + "cache-control": "max-age=31458789" + }, + { + "expires": "Sat, 02 Nov 2013 16:05:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5679" + }, + { + "cache-control": "public, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:31:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 31 Oct 2012 19:19:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7150" + }, + { + "cache-control": "max-age=31468533" + }, + { + "expires": "Sat, 02 Nov 2013 18:47:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 24 Oct 2012 05:51:41 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "5679" + }, + { + "cache-control": "max-age=30644382" + }, + { + "expires": "Thu, 24 Oct 2013 05:51:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 01 Nov 2012 21:24:39 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5636" + }, + { + "cache-control": "max-age=31450187" + }, + { + "expires": "Sat, 02 Nov 2013 13:41:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 01 Nov 2012 23:03:23 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7177" + }, + { + "cache-control": "max-age=31488510" + }, + { + "expires": "Sun, 03 Nov 2013 00:20:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 01 Nov 2012 18:41:38 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8702" + }, + { + "cache-control": "max-age=31321403" + }, + { + "expires": "Fri, 01 Nov 2013 01:55:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Fri, 12 Oct 2012 14:29:39 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "13046" + }, + { + "cache-control": "max-age=29637746" + }, + { + "expires": "Sat, 12 Oct 2013 14:14:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*tm63.%3C72om6%3E-13abcb35937-0x14e" + }, + { + "last-modified": "Tue, 30 Oct 2012 21:07:34 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "60906" + }, + { + "cache-control": "max-age=31372049" + }, + { + "expires": "Fri, 01 Nov 2013 15:59:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:58 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 18 Sep 2012 01:10:29 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "42205" + }, + { + "cache-control": "max-age=27517110" + }, + { + "expires": "Wed, 18 Sep 2013 01:10:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "53359" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "private, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:31:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "last-modified": "Tue, 16 Oct 2012 18:06:59 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "2583" + }, + { + "etag": "\"80e3ea8c9abcd1:639\"" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9vl*th%7Fbad%7F710-13ac67892f3-0x131" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "expires": "0" + }, + { + "set-cookie": "PS=T.0; Domain=main.ebayrtm.com; Expires=Sun, 03-Nov-2013 13:32:01 GMT; Path=/rtm" + }, + { + "location": "http://srx.main.ebayrtm.com/rtm?RtmCmd&a=json&l=@@__@@__@@&g=c67883f113a0a56964e646c6ffaa1ac1&c=1H4sIAAAAAAAAAB2OwWrCQBCG74LvMOClLXR3Zsckm8gevLR4SEuJhx5ySdMVg6krujXap%2B8kMDDD%2F%2F18zKJqIryFKyADpgVTkWRQVlswSGY%2BOzGjK8Nf1%2FeNThTCQ9m03TGGy34Fm2P0PUgA7xV8AqGyKzhf64JShY%2Fw6ttD0OJBGYKX7ux34aZHKGIyTlbbfTu29S9KR0LDS%2Fec5yO27BLKs%2BkkJw6cvjFuH%2BOpLrQehkH5r%2Bau2vAzIWkxKjK5Sq3KeMxs5vzmY90flk%2Fz2T9Cveg66wAAAA%3D%3D&p=11527:11528:11529&di=11527:11528:11529&v=4&enc=UTF-8&bm=286807&ord=1351949521580&cg=c67885c613a0a0a9f6568b16ff5917ee&cb=vjo.dsf.assembly.VjClientAssembler._callback0&_vrdm=1351949521581&r=yes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "expires": "Mon, 10 Dec 2012 02:40:28 GMT" + }, + { + "last-modified": "Thu, 09 Jul 2009 18:33:39 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "1406" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:56 GMT" + }, + { + "last-modified": "Mon, 13 Jul 2009 22:43:33 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"8018ba59b4ca1:5d2\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "386" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "last-modified": "Thu, 09 Jul 2009 18:33:41 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "3155" + }, + { + "etag": "\"80e3ea8c9abcd1:639\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9vl*th%7Fbad%7F715-13ac6789351-0x12a" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "4320" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "expires": "0" + }, + { + "set-cookie": "HT=1351949521580%0211529%04287876%06261345%0311528%04286823%06260443%0311527%04286801%06203908; Domain=main.ebayrtm.com; Path=/rtm" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "expires": "Mon, 26 Nov 2012 01:07:49 GMT" + }, + { + "last-modified": "Fri, 05 Oct 2012 18:48:16 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "92574" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:55 GMT" + }, + { + "last-modified": "Thu, 29 Mar 2012 22:36:00 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"048ac50fcdcd1:603\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "35128" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07m-133f0e5fedc-0x142" + }, + { + "last-modified": "Tue, 29 Nov 2011 19:19:17 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/css" + }, + { + "content-length": "545" + }, + { + "cache-control": "max-age=30563305" + }, + { + "expires": "Wed, 23 Oct 2013 07:20:26 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:02 GMT" + }, + { + "expires": "Tue, 18 Dec 2012 00:25:08 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 00:26:02 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "22428" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:02 GMT" + }, + { + "expires": "Tue, 18 Dec 2012 00:25:05 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 00:28:28 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "33895" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:02 GMT" + }, + { + "expires": "Mon, 17 Dec 2012 16:09:55 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 18:41:38 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "38761" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:02 GMT" + }, + { + "expires": "Mon, 17 Dec 2012 15:00:24 GMT" + }, + { + "last-modified": "Fri, 12 Oct 2012 14:28:46 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "60078" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750d%7F23-13abd599c11-0x167" + }, + { + "last-modified": "Mon, 29 Oct 2012 20:14:10 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "72619" + }, + { + "cache-control": "max-age=31382938" + }, + { + "expires": "Fri, 01 Nov 2013 19:00:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*tm63.%3C72om6%3E-13ac20abb51-0x14c" + }, + { + "last-modified": "Fri, 02 Nov 2012 16:52:54 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "69800" + }, + { + "cache-control": "max-age=31461635" + }, + { + "expires": "Sat, 02 Nov 2013 16:52:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:01 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "nonsession=CgAFMABhSdlBNNTA5NTFjY2QuMC4xLjEuMTQ5LjMuMC4xAMoAIFn7Hk1jNjc4ODNmMTEzYTBhNTY5NjRlNjQ2YzZmZmFhMWFjMQDLAAFQlSPVMX8u5Z8*; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:31:57 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "image/x-icon" + }, + { + "content-length": "1150" + }, + { + "date": "Sat, 03 Nov 2012 13:32:06 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 15:31:45 GMT" + }, + { + "last-modified": "Sat, 16 Aug 2003 20:42:27 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "49" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:55 GMT" + }, + { + "last-modified": "Thu, 18 Oct 2012 23:53:57 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80183dd68badcd1:720\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "2539" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "last-modified": "Thu, 30 Jul 2009 23:41:29 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "53" + }, + { + "etag": "\"80e3ea8c9abcd1:639\"" + }, + { + "expires": "Sat, 03 Nov 2012 15:14:28 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Mon, 26 Nov 2012 05:56:41 GMT" + }, + { + "last-modified": "Thu, 30 Jul 2009 23:41:33 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "53" + }, + { + "etag": "\"80b4fd446f11ca1:876\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:07 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "24567" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Sun, 16 Dec 2012 17:51:49 GMT" + }, + { + "last-modified": "Sun, 26 Feb 2012 07:40:00 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1968" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 16:37:50 GMT" + }, + { + "last-modified": "Tue, 07 Jul 2009 20:18:42 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "613" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:57 GMT" + }, + { + "last-modified": "Thu, 23 Aug 2007 20:40:22 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80183dd68badcd1:720\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "229" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Mon, 26 Nov 2012 05:56:41 GMT" + }, + { + "last-modified": "Thu, 04 Oct 2007 21:44:36 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "1887" + }, + { + "etag": "\"0bad4c1cf6c81:682\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 15:31:45 GMT" + }, + { + "last-modified": "Sat, 16 Aug 2003 20:42:27 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "49" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Mon, 19 Nov 2012 22:20:32 GMT" + }, + { + "last-modified": "Sat, 23 Apr 2011 09:37:40 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3936" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Thu, 13 Dec 2012 18:43:54 GMT" + }, + { + "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4059" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "expires": "Thu, 13 Dec 2012 18:24:38 GMT" + }, + { + "last-modified": "Thu, 09 Sep 2010 17:15:08 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4397" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 19 Jan 2012 01:26:02 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "10248" + }, + { + "cache-control": "max-age=22290839" + }, + { + "expires": "Fri, 19 Jul 2013 13:26:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 10 Nov 2011 13:27:41 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "1794" + }, + { + "cache-control": "max-age=16286156" + }, + { + "expires": "Sat, 11 May 2013 01:28:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sat, 19 May 2012 13:20:12 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2031" + }, + { + "cache-control": "max-age=4358180" + }, + { + "expires": "Mon, 24 Dec 2012 00:08:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 31 Oct 2012 14:04:13 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2394" + }, + { + "cache-control": "max-age=31533954" + }, + { + "expires": "Sun, 03 Nov 2013 12:58:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 04 Oct 2012 13:43:50 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3680" + }, + { + "cache-control": "max-age=31532824" + }, + { + "expires": "Sun, 03 Nov 2013 12:39:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sat, 16 Jun 2012 04:23:57 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3263" + }, + { + "cache-control": "max-age=10191966" + }, + { + "expires": "Fri, 01 Mar 2013 12:38:13 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 04 Sep 2012 13:46:03 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2469" + }, + { + "cache-control": "max-age=26067492" + }, + { + "expires": "Sun, 01 Sep 2013 06:30:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 17 Dec 2011 17:14:44 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "2521" + }, + { + "cache-control": "max-age=19496613" + }, + { + "expires": "Mon, 17 Jun 2013 05:15:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 15 Dec 2011 00:35:12 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "9133" + }, + { + "cache-control": "max-age=19263809" + }, + { + "expires": "Fri, 14 Jun 2013 12:35:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 29 Oct 2012 14:11:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3761" + }, + { + "cache-control": "max-age=31534424" + }, + { + "expires": "Sun, 03 Nov 2013 13:05:51 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sun, 23 Sep 2012 00:16:12 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2956" + }, + { + "cache-control": "max-age=27524859" + }, + { + "expires": "Wed, 18 Sep 2013 03:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 29 Oct 2012 14:13:08 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2236" + }, + { + "cache-control": "max-age=31105641" + }, + { + "expires": "Tue, 29 Oct 2013 13:59:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 07 May 2012 03:34:14 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1500" + }, + { + "cache-control": "max-age=4657042" + }, + { + "expires": "Thu, 27 Dec 2012 11:09:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 17 Oct 2012 21:46:06 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2528" + }, + { + "cache-control": "max-age=28697569" + }, + { + "expires": "Tue, 01 Oct 2013 17:04:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 02 Oct 2012 21:27:24 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1930" + }, + { + "cache-control": "max-age=28812498" + }, + { + "expires": "Thu, 03 Oct 2013 01:00:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sat, 20 Oct 2012 02:57:28 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1722" + }, + { + "cache-control": "max-age=30889406" + }, + { + "expires": "Sun, 27 Oct 2013 01:55:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 17 Jul 2012 14:30:13 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2961" + }, + { + "cache-control": "max-age=16431611" + }, + { + "expires": "Sun, 12 May 2013 17:52:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 24 Oct 2012 14:14:04 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2160" + }, + { + "cache-control": "max-age=30945129" + }, + { + "expires": "Sun, 27 Oct 2013 17:24:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 04 Oct 2012 14:11:43 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2841" + }, + { + "cache-control": "max-age=30221178" + }, + { + "expires": "Sat, 19 Oct 2013 08:18:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 07 May 2012 13:59:59 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1541" + }, + { + "cache-control": "max-age=7259332" + }, + { + "expires": "Sat, 26 Jan 2013 14:00:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 06 Jun 2012 14:05:14 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2123" + }, + { + "cache-control": "max-age=12334548" + }, + { + "expires": "Tue, 26 Mar 2013 07:47:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 04 Oct 2012 14:21:18 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "947" + }, + { + "cache-control": "max-age=27136636" + }, + { + "expires": "Fri, 13 Sep 2013 15:29:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 04 Oct 2012 14:45:15 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1846" + }, + { + "cache-control": "max-age=29813010" + }, + { + "expires": "Mon, 14 Oct 2013 14:55:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sat, 27 Oct 2012 14:17:41 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2166" + }, + { + "cache-control": "max-age=30506466" + }, + { + "expires": "Tue, 22 Oct 2013 15:33:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 04 Oct 2012 13:48:57 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3964" + }, + { + "cache-control": "max-age=31161579" + }, + { + "expires": "Wed, 30 Oct 2013 05:31:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 04 Oct 2012 13:43:32 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4653" + }, + { + "cache-control": "max-age=30556712" + }, + { + "expires": "Wed, 23 Oct 2013 05:30:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 11 Sep 2012 18:42:51 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "31476" + }, + { + "cache-control": "max-age=26975444" + }, + { + "expires": "Wed, 11 Sep 2013 18:42:51 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 17 Dec 2011 17:14:45 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "11181" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "max-age=19496528" + }, + { + "expires": "Mon, 17 Jun 2013 05:14:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 04 Oct 2012 14:19:33 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5580" + }, + { + "cache-control": "max-age=31535661" + }, + { + "expires": "Sun, 03 Nov 2013 13:26:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9vl*th%7Fbad%7F714-13ac678af80-0x141" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "903" + }, + { + "date": "Sat, 03 Nov 2012 13:32:08 GMT" + }, + { + "expires": "0" + }, + { + "set-cookie": "HT=1351949521580%0211529%04287876%06261345%0311528%04286823%06260443%0311527%04286801%06203908%011351949527269%02981%04-1%060%03980%04-1%060%03979%04-1%060%03688%04-1%060%03255%04-1%060; Domain=main.ebayrtm.com; Path=/rtm" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:09 GMT" + }, + { + "expires": "Mon, 17 Dec 2012 16:40:39 GMT" + }, + { + "last-modified": "Wed, 10 Jun 2009 16:58:56 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "1161" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:09 GMT" + }, + { + "expires": "Wed, 28 Nov 2012 05:06:23 GMT" + }, + { + "last-modified": "Sat, 16 May 2009 01:16:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "1180" + }, + { + "etag": "\"04864dfc3d5c91:5b1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "66" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Fri, 19 Jun 2009 17:50:32 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"064b8706f1c91:682\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "date": "Sat, 03 Nov 2012 13:32:09 GMT" + }, + { + "expires": "Sat, 27 Oct 2012 08:29:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:09 GMT" + }, + { + "expires": "Thu, 13 Dec 2012 19:35:46 GMT" + }, + { + "last-modified": "Thu, 17 Mar 2011 21:09:01 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "13713" + }, + { + "etag": "\"0bad4c1cf6c81:682\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 14 Feb 2012 08:00:47 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "53098" + }, + { + "cache-control": "max-age=24560912" + }, + { + "expires": "Wed, 14 Aug 2013 20:00:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sun, 28 Oct 2012 23:46:15 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "27209" + }, + { + "cache-control": "max-age=31054448" + }, + { + "expires": "Mon, 28 Oct 2013 23:46:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "text/html" + }, + { + "content-length": "397" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:32:10 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:10 GMT" + }, + { + "expires": "Sat, 15 Dec 2012 09:56:28 GMT" + }, + { + "last-modified": "Sat, 16 Aug 2003 20:42:27 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "49" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:10 GMT" + }, + { + "last-modified": "Mon, 08 Mar 2010 19:32:35 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "146" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 22 Oct 2012 20:38:55 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1918" + }, + { + "cache-control": "max-age=30051310" + }, + { + "expires": "Thu, 17 Oct 2013 09:07:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 01 Nov 2012 18:00:33 GMT" + }, + { + "date": "Fri, 02 Nov 2012 18:12:07 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 18:12:07 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "26810" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "69603" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "content-type": "image/x-icon" + }, + { + "content-length": "1150" + }, + { + "date": "Sat, 03 Nov 2012 13:32:11 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "expires": "Mon, 26 Nov 2012 00:29:24 GMT" + }, + { + "last-modified": "Fri, 18 Mar 2005 23:03:54 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "260" + }, + { + "etag": "\"04864dfc3d5c91:5b1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "expires": "Tue, 11 Dec 2012 20:45:48 GMT" + }, + { + "last-modified": "Fri, 27 Aug 2010 00:22:53 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80183dd68badcd1:720\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "366" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "last-modified": "Fri, 18 Mar 2005 23:04:39 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "172" + }, + { + "etag": "\"80e3ea8c9abcd1:639\"" + }, + { + "expires": "Tue, 06 Nov 2012 16:57:28 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:12 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "90925" + }, + { + "date": "Sat, 03 Nov 2012 13:32:11 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "expires": "Thu, 13 Dec 2012 19:00:40 GMT" + }, + { + "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "11504" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "expires": "Thu, 13 Dec 2012 19:00:40 GMT" + }, + { + "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "11504" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 18 Oct 2012 22:46:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3962" + }, + { + "cache-control": "max-age=29068398" + }, + { + "expires": "Sun, 06 Oct 2013 00:05:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:53:50 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4670" + }, + { + "cache-control": "max-age=31276058" + }, + { + "expires": "Thu, 31 Oct 2013 13:19:50 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 11 Oct 2012 01:52:55 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5679" + }, + { + "cache-control": "max-age=28834042" + }, + { + "expires": "Thu, 03 Oct 2013 06:59:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 25 Jul 2012 20:50:41 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3929" + }, + { + "cache-control": "max-age=17978904" + }, + { + "expires": "Thu, 30 May 2013 15:40:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 06 Aug 2012 06:13:28 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2473" + }, + { + "cache-control": "max-age=22036778" + }, + { + "expires": "Tue, 16 Jul 2013 14:51:50 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6172" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "private, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:32:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 16 Mar 2012 00:40:23 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "52950" + }, + { + "cache-control": "max-age=27212892" + }, + { + "expires": "Sat, 14 Sep 2013 12:40:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sun, 27 May 2012 12:26:18 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6163" + }, + { + "cache-control": "max-age=17941535" + }, + { + "expires": "Thu, 30 May 2013 05:17:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 13 Aug 2012 06:52:35 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4526" + }, + { + "cache-control": "max-age=24498920" + }, + { + "expires": "Wed, 14 Aug 2013 02:47:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "48924" + }, + { + "cache-control": "public, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:32:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:14 GMT" + }, + { + "expires": "Mon, 17 Dec 2012 16:40:39 GMT" + }, + { + "last-modified": "Wed, 19 Oct 2011 00:48:19 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "275" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "1145" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Tue, 15 Feb 2011 17:36:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80b7dad536cdcb1:854\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "date": "Sat, 03 Nov 2012 13:32:14 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:55 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:14 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 04:59:25 GMT" + }, + { + "last-modified": "Wed, 02 Feb 2011 19:43:17 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80183dd68badcd1:720\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "3546" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:14 GMT" + }, + { + "expires": "Thu, 27 Sep 2012 23:15:40 GMT" + }, + { + "last-modified": "Fri, 21 Jan 2011 20:52:52 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "6342" + }, + { + "etag": "\"0aa782badb9cb1:682\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:14 GMT" + }, + { + "last-modified": "Thu, 09 Sep 2010 03:40:20 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "10896" + }, + { + "etag": "\"80e3ea8c9abcd1:639\"" + }, + { + "expires": "Sun, 16 Dec 2012 05:44:38 GMT" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:14 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:57 GMT" + }, + { + "last-modified": "Fri, 22 Jun 2012 22:09:21 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "59719" + }, + { + "etag": "\"04864dfc3d5c91:5b1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:14 GMT" + }, + { + "last-modified": "Fri, 22 Jun 2012 22:09:21 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "59719" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:57 GMT" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4n%60rujfudlwc%3D9vt*ts67.62d5%3C%3E7-13ac678c943-0x1a4" + }, + { + "cache-control": "private, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/json" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:32:14 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:16 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/javascript;charset=UTF-8" + }, + { + "content-length": "80046" + }, + { + "date": "Sat, 03 Nov 2012 13:32:15 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "uk.r+607b~`s,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7E%60s-13ac678cb27-0xb7" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Mon, 17 Dec 2012 13:46:54 GMT" + }, + { + "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "739" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Thu, 22 Nov 2012 14:19:41 GMT" + }, + { + "last-modified": "Sat, 23 Apr 2011 09:37:40 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1649" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 06:10:27 GMT" + }, + { + "last-modified": "Fri, 18 Mar 2005 23:01:04 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "134" + }, + { + "etag": "\"078525ce2cc51:586\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Fri, 14 Dec 2012 05:08:13 GMT" + }, + { + "last-modified": "Fri, 21 Oct 2005 18:47:40 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "231" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Sun, 09 Dec 2012 06:52:18 GMT" + }, + { + "last-modified": "Tue, 06 Sep 2005 19:37:46 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80183dd68badcd1:720\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "643" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Fri, 26 Oct 2012 04:43:31 GMT" + }, + { + "last-modified": "Thu, 06 Oct 2005 21:29:14 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "369" + }, + { + "etag": "\"0aa782badb9cb1:682\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "199" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Fri, 21 Oct 2005 18:47:42 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80b7dad536cdcb1:854\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:55 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "last-modified": "Wed, 04 Mar 2009 03:12:30 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "2388" + }, + { + "etag": "\"80e3ea8c9abcd1:639\"" + }, + { + "expires": "Sun, 16 Dec 2012 05:44:38 GMT" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Mon, 19 Nov 2012 22:20:46 GMT" + }, + { + "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1713" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Sun, 11 Nov 2012 06:40:21 GMT" + }, + { + "last-modified": "Thu, 09 Sep 2010 17:30:38 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1389" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Mon, 26 Nov 2012 04:31:42 GMT" + }, + { + "last-modified": "Fri, 18 Mar 2005 23:04:34 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "141" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:56 GMT" + }, + { + "last-modified": "Fri, 18 Mar 2005 23:05:11 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "136" + }, + { + "etag": "\"80ad8befe2cc51:8e4\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Thu, 29 Nov 2012 16:39:21 GMT" + }, + { + "last-modified": "Tue, 02 Aug 2011 07:55:09 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6651" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:16 GMT" + }, + { + "expires": "Thu, 06 Dec 2012 09:42:11 GMT" + }, + { + "last-modified": "Mon, 28 Mar 2011 14:55:59 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "13825" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "last-modified": "Sat, 16 Aug 2003 20:42:25 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "49" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:57 GMT" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890;Domain=.ebay.com;Expires=Thu, 02-Nov-2017 13:32:21 GMT;Path=/ " + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "80046" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "uk.r+607b~`s,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7E%60s-13ac678cb27-0xb7" + }, + { + "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "expires": "Sun, 18 Nov 2012 22:28:04 GMT" + }, + { + "last-modified": "Thu, 04 Oct 2007 21:44:39 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "3179" + }, + { + "etag": "\"078525ce2cc51:586\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "last-modified": "Fri, 27 Aug 2010 00:22:48 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "391" + }, + { + "expires": "Sat, 03 Nov 2012 15:13:22 GMT" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "last-modified": "Fri, 18 Mar 2005 23:05:11 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "136" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "last-modified": "Thu, 06 Sep 2007 00:11:47 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "542" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:55 GMT" + }, + { + "last-modified": "Thu, 06 Jul 2006 00:07:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0aa151a90a0c61:5e2\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "43" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "last-modified": "Tue, 24 May 2011 22:33:41 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "1351" + }, + { + "expires": "Sat, 03 Nov 2012 15:13:22 GMT" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "last-modified": "Thu, 06 Sep 2007 00:21:31 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80f7a0df1bf0c71:5b1\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "6386" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 25 Oct 2012 23:31:47 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "3276" + }, + { + "cache-control": "max-age=30794366" + }, + { + "expires": "Fri, 25 Oct 2013 23:31:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 25 Oct 2012 23:31:47 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "668" + }, + { + "cache-control": "max-age=30794366" + }, + { + "expires": "Fri, 25 Oct 2013 23:31:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 14 Jul 2012 00:50:47 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "44" + }, + { + "cache-control": "max-age=21813506" + }, + { + "expires": "Sun, 14 Jul 2013 00:50:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:56 GMT" + }, + { + "last-modified": "Tue, 02 Feb 2010 19:44:14 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "13817" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-language": "cs-CZ" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6172" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "private, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:32:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 03:28:30 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "6661" + }, + { + "cache-control": "max-age=31413369" + }, + { + "expires": "Sat, 02 Nov 2013 03:28:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 06 Jul 2012 01:08:44 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "351" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "max-age=21123378" + }, + { + "expires": "Sat, 06 Jul 2013 01:08:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 22 Oct 2012 03:07:31 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4553" + }, + { + "cache-control": "max-age=29866596" + }, + { + "expires": "Tue, 15 Oct 2013 05:48:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sat, 22 Sep 2012 19:51:38 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4694" + }, + { + "cache-control": "max-age=24377502" + }, + { + "expires": "Mon, 12 Aug 2013 17:04:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 30 Oct 2012 21:48:15 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5307" + }, + { + "cache-control": "max-age=31498703" + }, + { + "expires": "Sun, 03 Nov 2013 03:10:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 25 Oct 2012 23:32:05 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "3014" + }, + { + "cache-control": "max-age=30794343" + }, + { + "expires": "Fri, 25 Oct 2013 23:31:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "expires": "Tue, 18 Dec 2012 13:32:22 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:53:41 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "15981" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "expires": "Sun, 18 Nov 2012 22:28:04 GMT" + }, + { + "last-modified": "Fri, 25 Jun 2010 01:28:28 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "578" + }, + { + "etag": "\"0c688b6514cb1:586\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-language": "pt-BR" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9688" + }, + { + "cache-control": "public, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:32:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:21 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "last-modified": "Tue, 20 Sep 2011 23:59:47 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "1780" + }, + { + "etag": "\"80e3ea8c9abcd1:639\"" + }, + { + "expires": "Mon, 26 Nov 2012 00:03:41 GMT" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07p-139944fe49b-0x176" + }, + { + "last-modified": "Thu, 23 Aug 2012 17:24:32 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/css" + }, + { + "content-length": "8722" + }, + { + "cache-control": "max-age=26399474" + }, + { + "expires": "Thu, 05 Sep 2013 02:43:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "last-modified": "Wed, 12 Jan 2011 20:27:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "342" + }, + { + "expires": "Mon, 26 Nov 2012 16:35:19 GMT" + }, + { + "cache-control": "max-age=3888000" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:55 GMT" + }, + { + "last-modified": "Wed, 19 Oct 2011 01:17:47 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "6641" + }, + { + "etag": "\"80af29e9fc8dcc1:8e4\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 11 Jul 2012 18:03:37 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2752" + }, + { + "cache-control": "max-age=14608007" + }, + { + "expires": "Sun, 21 Apr 2013 15:19:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "last-modified": "Tue, 07 Jul 2009 20:18:42 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "613" + }, + { + "expires": "Mon, 26 Nov 2012 16:35:19 GMT" + }, + { + "cache-control": "max-age=3888000" + }, + { + "etag": "\"03d21f40ffc91:5b1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 12 Jul 2012 22:44:28 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "551" + }, + { + "cache-control": "max-age=21719526" + }, + { + "expires": "Fri, 12 Jul 2013 22:44:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "expires": "Mon, 17 Dec 2012 20:39:34 GMT" + }, + { + "last-modified": "Tue, 20 Sep 2011 02:08:20 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80183dd68badcd1:720\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "17673" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B4%603g-13ac678e4f2-0x104" + }, + { + "set-cookie": "nonsession=CgADLAAFQlSPuMQDKACBZ+x5mYzY3OGU0YzgxM2EwYTVlNmM4ZDZjODQ2ZmZmOGYzYjlPrxuR;Domain=.raptor.ebaydesc.com;Expires=Sun, 03-Nov-2013 13:32:22 GMT;Path=/ " + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 00:03:20 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "54313" + }, + { + "cache-control": "max-age=31401067" + }, + { + "expires": "Sat, 02 Nov 2013 00:03:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 02 Nov 2012 00:03:52 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "20701" + }, + { + "cache-control": "max-age=31401093" + }, + { + "expires": "Sat, 02 Nov 2013 00:03:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9ve*t%28747%60e%7E%3A-13ac678e523-0x15c" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "3577" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "expires": "0" + }, + { + "set-cookie": "HT=1351949521580%0211529%04287876%06261345%0311528%04286823%06260443%0311527%04286801%06203908%011351949527269%02981%04-1%060%03980%04-1%060%03979%04-1%060%03688%04-1%060%03255%04-1%060%011351949541760%0211575%04-1%060%031527%04-1%060%03829%04-1%060%03912%04-1%060%03827%04-1%060%03876%04-1%060%03825%04-1%060%03433%04-1%060%031651%04-1%060%031650%04-1%060; Domain=main.ebayrtm.com; Path=/rtm" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 29 Oct 2012 21:23:48 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "5138" + }, + { + "cache-control": "max-age=31132229" + }, + { + "expires": "Tue, 29 Oct 2013 21:22:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "last-modified": "Thu, 04 Oct 2007 21:44:39 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "3179" + }, + { + "expires": "Fri, 14 Dec 2012 20:03:15 GMT" + }, + { + "cache-control": "max-age=3888000" + }, + { + "etag": "\"03d21f40ffc91:5b1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:23 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/javascript;charset=UTF-8" + }, + { + "content-length": "7004" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "uk.r+607b~`s,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7E%60s-13ac678cb27-0xb7" + }, + { + "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:47:00 GMT" + }, + { + "last-modified": "Fri, 27 Aug 2010 00:22:54 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "366" + }, + { + "etag": "\"80af29e9fc8dcc1:8e4\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "expires": "Fri, 26 Oct 2012 04:43:31 GMT" + }, + { + "last-modified": "Thu, 06 Oct 2005 21:29:14 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80fb69e73664c31:6fe\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "141" + }, + { + "cache-control": "max-age=3888000" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "last-modified": "Mon, 25 Jul 2005 20:31:43 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "64" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:59 GMT" + }, + { + "cache-control": "max-age=3888000" + }, + { + "etag": "\"03d21f40ffc91:5b1\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "expires": "Sun, 18 Nov 2012 22:28:04 GMT" + }, + { + "last-modified": "Tue, 25 Sep 2012 05:16:18 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "7623" + }, + { + "etag": "\"0c688b6514cb1:586\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Fri, 19 Oct 2012 22:52:32 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "949" + }, + { + "cache-control": "max-age=30273610" + }, + { + "expires": "Sat, 19 Oct 2013 22:52:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Tue, 19 Jun 2012 05:08:42 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1069" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "max-age=19670318" + }, + { + "expires": "Wed, 19 Jun 2013 05:31:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Thu, 25 Oct 2012 03:14:23 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "6931" + }, + { + "cache-control": "max-age=30721319" + }, + { + "expires": "Fri, 25 Oct 2013 03:14:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:23 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlog": "uh%60jk%3D9vj*ts67.21336g2-13ac678eef8" + }, + { + "x-ebay-request-id": "13ac678e-ef80-a5ac-0760-c260ff104b3e!ajax.all.get!10.90.192.118!ebay.com[]" + }, + { + "content-type": "application/json" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:32:24 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:25 GMT" + }, + { + "expires": "Sun, 18 Nov 2012 22:28:04 GMT" + }, + { + "last-modified": "Thu, 04 Oct 2012 18:56:36 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "9521" + }, + { + "etag": "\"0c688b6514cb1:586\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4n%60rujfudlwc%3D9un%7F4g65%60%283ab%3D-13ac678ef91-0x19c" + }, + { + "cache-control": "private, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/json" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:32:25 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:30 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "90235" + }, + { + "date": "Sat, 03 Nov 2012 13:32:30 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "uk.r+607b~`s,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7E%60s-13ac678cb27-0xb7" + }, + { + "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "date": "Sat, 03 Nov 2012 13:32:31 GMT" + }, + { + "expires": "Thu, 27 Sep 2012 23:15:40 GMT" + }, + { + "last-modified": "Fri, 21 Jan 2011 20:52:52 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "366" + }, + { + "etag": "\"0aa782badb9cb1:682\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:32 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/javascript;charset=UTF-8" + }, + { + "content-length": "80050" + }, + { + "date": "Sat, 03 Nov 2012 13:32:31 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "uk.r+607b~go,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7Ego-13ac6790aa0-0xb6" + }, + { + "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "date": "Sat, 03 Nov 2012 13:32:32 GMT" + }, + { + "expires": "Fri, 26 Oct 2012 04:43:31 GMT" + }, + { + "last-modified": "Thu, 06 Oct 2005 21:29:14 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "366" + }, + { + "etag": "\"0aa782badb9cb1:682\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:32 GMT" + }, + { + "expires": "Fri, 14 Dec 2012 13:33:03 GMT" + }, + { + "last-modified": "Wed, 02 May 2012 23:09:29 GMT" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1544" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4n%60rujfudlwc%3D9un%7F4g65%60%28c1eg-13ac67910d1-0x179" + }, + { + "cache-control": "private, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:32:32 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 29 May 2012 21:33:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4908" + }, + { + "cache-control": "max-age=8305824" + }, + { + "expires": "Thu, 07 Feb 2013 16:42:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:33 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:36 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "91130" + }, + { + "date": "Sat, 03 Nov 2012 13:32:36 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "uk.r+607b~go,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7Ego-13ac6790aa0-0xb6" + }, + { + "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "date": "Sat, 03 Nov 2012 13:32:37 GMT" + }, + { + "expires": "Thu, 27 Sep 2012 23:15:40 GMT" + }, + { + "last-modified": "Fri, 21 Jan 2011 20:52:52 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "366" + }, + { + "etag": "\"0aa782badb9cb1:682\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:37 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/javascript;charset=UTF-8" + }, + { + "content-length": "80060" + }, + { + "date": "Sat, 03 Nov 2012 13:32:37 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "v .r+616d2tu,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fv%7F.r%2B616d2tu-13ac6791ff9-0xbc" + }, + { + "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "date": "Sat, 03 Nov 2012 13:32:38 GMT" + }, + { + "expires": "Fri, 26 Oct 2012 04:43:31 GMT" + }, + { + "last-modified": "Thu, 06 Oct 2005 21:29:14 GMT" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "366" + }, + { + "etag": "\"0aa782badb9cb1:682\"" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1290" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "private, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:32:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:39 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cteonnt-length": "4588" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4n%60rujfudlwc%3D9un%7F4g66%60%283d30-13ac67928dc-0x197" + }, + { + "cache-control": "private, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:32:39 GMT" + }, + { + "content-length": "42" + }, + { + "set-cookie": "npii=btguid/c67883f113a0a56964e646c6ffaa1ac152765078^cguid/c67885c613a0a0a9f6568b16ff5917ee52765078^; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:32:40 GMT; Path=/" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa ADMa DEVa PSDo PSAa OUR SAMo IND UNI COM NAV INT STA DEM PRE\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:39 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "91165" + }, + { + "date": "Sat, 03 Nov 2012 13:32:39 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "v .r+616d2tu,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fv%7F.r%2B616d2tu-13ac6791ff9-0xbc" + }, + { + "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4n%60rujfudlwc%3D9un%7F4g65%60%28555f-13ac6792d15-0x18d" + }, + { + "cache-control": "private, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:32:41 GMT" + }, + { + "content-length": "42" + }, + { + "set-cookie": "npii=bcguid/c67885c613a0a0a9f6568b16ff5917ee52765079^tguid/c67883f113a0a56964e646c6ffaa1ac152765079^; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:32:41 GMT; Path=/" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa ADMa DEVa PSDo PSAa OUR SAMo IND UNI COM NAV INT STA DEM PRE\"" + } + ] + }, + { + "headers": [ + { + ":status": "301" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:42 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://www.ebay.com/fashion/health-beauty" + }, + { + "rlogid": "p4pmiw%60jtb9%3Fv%7F.wcc%60dh72%3C-13ac6793402" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:32:42 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:43 GMT; Path=/" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-length": "12792" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "v .r+616d2tu,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fv%7F.r%2B616d2tu-13ac6791ff9-0xbc" + }, + { + "rlogid": "p4u%60tsjfgkpfiuf%3F%3Ctq%28qq.d%605g%6053-13ac679336d" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:47:45 GMT" + }, + { + "last-modified": "Thu, 05 Jul 2012 18:43:18 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "2469" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 24 May 2012 16:22:27 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5850" + }, + { + "cache-control": "max-age=31509956" + }, + { + "expires": "Sun, 03 Nov 2013 06:18:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5679" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "public, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:32:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cteonnt-length": "4588" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sat, 27 Oct 2012 15:54:54 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6322" + }, + { + "cache-control": "max-age=31522197" + }, + { + "expires": "Sun, 03 Nov 2013 09:42:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07n-13aac9b9c70-0x176" + }, + { + "last-modified": "Wed, 24 Oct 2012 22:29:19 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "250" + }, + { + "cache-control": "max-age=31102053" + }, + { + "expires": "Tue, 29 Oct 2013 13:00:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 26 Dec 2011 17:33:25 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5900" + }, + { + "cache-control": "max-age=31504816" + }, + { + "expires": "Sun, 03 Nov 2013 04:52:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 29 Oct 2012 15:32:58 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3953" + }, + { + "cache-control": "max-age=31511815" + }, + { + "expires": "Sun, 03 Nov 2013 06:49:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Fri, 12 Oct 2012 17:37:08 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4418" + }, + { + "cache-control": "max-age=29623692" + }, + { + "expires": "Sat, 12 Oct 2013 10:20:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10098" + }, + { + "cache-control": "private, max-age=31536000" + }, + { + "expires": "Sun, 03 Nov 2013 13:32:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "last-modified": "Tue, 07 Aug 2012 21:01:25 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"804039cedf74cd1:603\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "113266" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 07 Aug 2012 05:29:55 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7341" + }, + { + "cache-control": "max-age=19386157" + }, + { + "expires": "Sat, 15 Jun 2013 22:35:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 23 Oct 2012 21:57:15 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7462" + }, + { + "cache-control": "max-age=31508534" + }, + { + "expires": "Sun, 03 Nov 2013 05:54:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 29 Oct 2012 02:39:26 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "10090" + }, + { + "cache-control": "max-age=31501318" + }, + { + "expires": "Sun, 03 Nov 2013 03:54:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 16 Oct 2012 19:32:45 GMT" + }, + { + "content-type": "text/css;charset=UTF-8" + }, + { + "content-length": "6377" + }, + { + "cache-control": "max-age=30002402" + }, + { + "expires": "Wed, 16 Oct 2013 19:32:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 29 May 2012 19:40:07 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4488" + }, + { + "cache-control": "max-age=7260395" + }, + { + "expires": "Sat, 26 Jan 2013 14:19:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Fri, 20 Jul 2012 23:29:38 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4889" + }, + { + "cache-control": "max-age=19908420" + }, + { + "expires": "Fri, 21 Jun 2013 23:39:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 09 Oct 2012 14:02:17 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3638" + }, + { + "cache-control": "max-age=28507880" + }, + { + "expires": "Sun, 29 Sep 2013 12:24:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 02 Oct 2012 18:02:08 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5356" + }, + { + "cache-control": "max-age=29198995" + }, + { + "expires": "Mon, 07 Oct 2013 12:22:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 12 Jul 2012 01:56:06 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4607" + }, + { + "cache-control": "max-age=20432905" + }, + { + "expires": "Fri, 28 Jun 2013 01:21:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 23 Jul 2012 16:18:08 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5128" + }, + { + "cache-control": "max-age=23738740" + }, + { + "expires": "Mon, 05 Aug 2013 07:38:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 29 Oct 2012 16:44:35 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7892" + }, + { + "cache-control": "max-age=31534799" + }, + { + "expires": "Sun, 03 Nov 2013 13:12:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 16 Oct 2012 03:33:23 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4234" + }, + { + "cache-control": "max-age=29726488" + }, + { + "expires": "Sun, 13 Oct 2013 14:54:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 20 Aug 2012 20:26:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3021" + }, + { + "cache-control": "max-age=26204352" + }, + { + "expires": "Mon, 02 Sep 2013 20:31:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Fri, 28 Sep 2012 15:22:25 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4919" + }, + { + "cache-control": "max-age=30719689" + }, + { + "expires": "Fri, 25 Oct 2013 02:47:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sun, 22 Jul 2012 18:13:25 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4788" + }, + { + "cache-control": "max-age=20831615" + }, + { + "expires": "Tue, 02 Jul 2013 16:06:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Fri, 06 Jul 2012 20:15:28 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3987" + }, + { + "cache-control": "max-age=17873930" + }, + { + "expires": "Wed, 29 May 2013 10:31:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 16 Aug 2012 14:53:01 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4623" + }, + { + "cache-control": "max-age=20477655" + }, + { + "expires": "Fri, 28 Jun 2013 13:46:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Fri, 27 Jul 2012 17:58:05 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4821" + }, + { + "cache-control": "max-age=20499738" + }, + { + "expires": "Fri, 28 Jun 2013 19:55:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Fri, 13 Jul 2012 05:37:24 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5080" + }, + { + "cache-control": "max-age=19887245" + }, + { + "expires": "Fri, 21 Jun 2013 17:46:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:02:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "18863" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "max-age=40850" + }, + { + "expires": "Sun, 04 Nov 2012 00:53:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Thu, 27 Sep 2012 13:24:40 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "10030" + }, + { + "cache-control": "max-age=31521522" + }, + { + "expires": "Sun, 03 Nov 2013 09:31:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 16 Jul 2012 07:04:19 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6320" + }, + { + "cache-control": "max-age=23373247" + }, + { + "expires": "Thu, 01 Aug 2013 02:06:51 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "connection": "keep-alive" + }, + { + "access-control-allow-origin": "*" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g3%7E1-13a3ef29997-0x16d" + }, + { + "last-modified": "Fri, 05 Oct 2012 05:17:21 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "60127" + }, + { + "cache-control": "max-age=29262216" + }, + { + "expires": "Tue, 08 Oct 2013 05:56:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Tue, 10 Jul 2012 21:28:46 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5983" + }, + { + "cache-control": "max-age=23738926" + }, + { + "expires": "Mon, 05 Aug 2013 07:41:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Sat, 27 Oct 2012 14:51:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "11895" + }, + { + "cache-control": "max-age=31510005" + }, + { + "expires": "Sun, 03 Nov 2013 06:19:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 22 Oct 2012 08:46:05 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7674" + }, + { + "cache-control": "max-age=31245727" + }, + { + "expires": "Thu, 31 Oct 2013 04:54:50 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Wed, 08 Aug 2012 18:20:46 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "12744" + }, + { + "cache-control": "max-age=26388803" + }, + { + "expires": "Wed, 04 Sep 2013 23:46:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Mon, 27 Aug 2012 19:38:43 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5852" + }, + { + "cache-control": "max-age=27384452" + }, + { + "expires": "Mon, 16 Sep 2013 12:20:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Tue, 22 Nov 2011 18:32:07 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6016" + }, + { + "cache-control": "max-age=31505442" + }, + { + "expires": "Sun, 03 Nov 2013 05:03:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sun, 23 Sep 2012 20:27:09 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8741" + }, + { + "cache-control": "max-age=28128091" + }, + { + "expires": "Wed, 25 Sep 2013 02:54:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Thu, 25 Oct 2012 18:53:28 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5727" + }, + { + "cache-control": "max-age=31502723" + }, + { + "expires": "Sun, 03 Nov 2013 04:18:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Tue, 16 Oct 2012 19:32:46 GMT" + }, + { + "content-type": "application/x-javascript;charset=UTF-8" + }, + { + "content-length": "54418" + }, + { + "cache-control": "max-age=30002439" + }, + { + "expires": "Wed, 16 Oct 2013 19:33:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "last-modified": "Tue, 22 May 2012 19:02:53 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "2288" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "expires": "Sun, 25 Nov 2012 23:46:56 GMT" + }, + { + "last-modified": "Wed, 31 Aug 2011 00:39:15 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "cache-control": "max-age=3888000" + }, + { + "content-length": "5743" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sun, 15 Jul 2012 05:26:27 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6174" + }, + { + "cache-control": "max-age=20606181" + }, + { + "expires": "Sun, 30 Jun 2013 01:29:05 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "last-modified": "Sun, 28 Oct 2012 20:13:40 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8182" + }, + { + "cache-control": "max-age=30802674" + }, + { + "expires": "Sat, 26 Oct 2013 01:50:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g065-13911ec26be-0x16d" + }, + { + "last-modified": "Wed, 08 Aug 2012 21:42:19 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "58636" + }, + { + "cache-control": "max-age=24211902" + }, + { + "expires": "Sat, 10 Aug 2013 19:04:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "last-modified": "Wed, 03 Oct 2012 22:05:50 GMT" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"804039cedf74cd1:603\"" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "content-length": "63909" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "*" + }, + { + "last-modified": "Mon, 29 Oct 2012 15:58:50 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "13008" + }, + { + "cache-control": "max-age=31535919" + }, + { + "expires": "Sun, 03 Nov 2013 13:31:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4n%60rujfudlwc%3D9vt*ts67.4e6f0e0-13ac6793f33-0x19b" + }, + { + "cache-control": "private, no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:32:45 GMT" + }, + { + "content-length": "42" + }, + { + "set-cookie": "npii=btguid/c67883f113a0a56964e646c6ffaa1ac15276507d^cguid/c67885c613a0a0a9f6568b16ff5917ee5276507d^; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:32:45 GMT; Path=/" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa ADMa DEVa PSDo PSAa OUR SAMo IND UNI COM NAV INT STA DEM PRE\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "rlogid": "p4pphdlwc%3D9u%7E*t%28750g3%7Fo-13a40772552-0x169" + }, + { + "last-modified": "Fri, 05 Oct 2012 05:19:14 GMT" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "115864" + }, + { + "cache-control": "max-age=29287759" + }, + { + "expires": "Tue, 08 Oct 2013 13:02:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:32:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "2703" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Wed, 28 Mar 2012 22:30:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "date": "Sat, 03 Nov 2012 13:32:44 GMT" + }, + { + "expires": "Tue, 30 Oct 2012 19:27:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:58 GMT; Path=/" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/javascript;charset=UTF-8" + }, + { + "content-length": "80064" + }, + { + "date": "Sat, 03 Nov 2012 13:32:58 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT" + }, + { + "transaction": "uk.r+607b~k|,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7Ek%7C-13ac6796fd6-0xc1" + }, + { + "rlogid": "p4u%60tsjfgkpfiuf%3F%3Ctq%28qq.d%605g%6053-13ac679336d" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_26.json b/jetty-http2/http2-hpack/src/test/resources/data/story_26.json new file mode 100644 index 00000000000..143ced203fc --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_26.json @@ -0,0 +1,4439 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "522" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:20 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "IVe/SwucJuBsLtVHWJw2PMdOTOxuEWUir5igQNThkTg=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=17216869" + }, + { + "expires": "Tue, 21 May 2013 19:18:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Tue, 24 Apr 2012 22:13:35 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "95tUymdadFLd8Dpml8VnOoUG7KhisOwk74Kd/aIGfU0=" + }, + { + "x-cnection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "123" + }, + { + "cache-control": "public, max-age=16394910" + }, + { + "expires": "Sun, 12 May 2013 06:59:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:37:35 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "Qc0GcUiwi3io8aSRIdXaahYr6KKhphvV6NlN8vo/bD4=" + }, + { + "content-length": "14684" + }, + { + "cache-control": "public, max-age=31067635" + }, + { + "expires": "Tue, 29 Oct 2013 02:44:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:23 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "7exUqkoZxtfLseR1zLxJlXnpYK6MOognZuCKx7drdRo=" + }, + { + "content-length": "14438" + }, + { + "cache-control": "public, max-age=24926560" + }, + { + "expires": "Mon, 19 Aug 2013 00:53:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Mon, 29 Oct 2012 17:08:56 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "eRvyJLXIvW3Vu9d+m439v+LGKqXiLSKmz7w9/xMAUpc=" + }, + { + "content-length": "17475" + }, + { + "cache-control": "public, max-age=31124427" + }, + { + "expires": "Tue, 29 Oct 2013 18:31:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 22:55:27 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "14hoEcywNNMBIVUS5B7AD7RDGiDvJ4BGeOVgJbBDzf0=" + }, + { + "content-length": "44191" + }, + { + "cache-control": "public, max-age=31067635" + }, + { + "expires": "Tue, 29 Oct 2013 02:44:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Fri, 12 Oct 2012 18:34:48 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "41/HuGcFNMmys4cvGKlBeylojdVDP4+VBIf1giu3eNQ=" + }, + { + "content-length": "754" + }, + { + "cache-control": "public, max-age=29985162" + }, + { + "expires": "Wed, 16 Oct 2013 14:03:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 25 Oct 2012 16:05:53 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "oKQwv0JLYost+zqlv8x+C7MEL7zRBbeMomoc54M5RZY=" + }, + { + "x-cnection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2349" + }, + { + "cache-control": "public, max-age=31067361" + }, + { + "expires": "Tue, 29 Oct 2013 02:40:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "2626" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:08:50 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "zh8tRHKFtERIZ+K/eGiM1utm1H66OnOj1qwPAN7Ck9A=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=31068570" + }, + { + "expires": "Tue, 29 Oct 2013 03:00:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Fri, 28 Sep 2012 15:01:14 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "pricqIchHztHxKAQSidQiwGmRf62vAL6I7Oi0r/Ki08=" + }, + { + "content-length": "8036" + }, + { + "cache-control": "public, max-age=31066940" + }, + { + "expires": "Tue, 29 Oct 2013 02:33:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:42:19 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "Kur2FUUQjAQ0yPQJC9fvK56/+LWZHvyQF6Ce2Fuaf2k=" + }, + { + "content-length": "36302" + }, + { + "cache-control": "public, max-age=31068470" + }, + { + "expires": "Tue, 29 Oct 2013 02:58:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:02:51 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "wk2MWysJhw3Et7CRGMA1sE9HWuyzy8oCvtT2V7iPXeg=" + }, + { + "content-length": "8230" + }, + { + "cache-control": "public, max-age=25639699" + }, + { + "expires": "Tue, 27 Aug 2013 06:59:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:38:44 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "GMzzyj0B89LYf1zKH9hqxZekz5mYTmsuxwLugWyc2Gg=" + }, + { + "content-length": "4878" + }, + { + "cache-control": "public, max-age=31068529" + }, + { + "expires": "Tue, 29 Oct 2013 02:59:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:37:48 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 04:37:48 GMT" + }, + { + "content-type": "application/ocsp-response" + }, + { + "content-transfer-encoding": "binary" + }, + { + "content-length": "1814" + }, + { + "cache-control": "max-age=575215, public, no-transform, must-revalidate" + }, + { + "date": "Sat, 03 Nov 2012 12:50:53 GMT" + }, + { + "nncoection": "close" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":53,\"r\":26,\"q\":0,\"a\":25}" + }, + { + "x-fb-server": "10.74.89.23" + }, + { + "x-fb-debug": "7iLjsQVXsunUKXe3NlV2ytaBGzQ0VHCkMX/J6rEuB6Y=" + }, + { + "date": "Sat, 03 Nov 2012 12:50:54 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "43" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 15:06:53 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "ur+THlFHeLotsmDlQWYPw2GRELyvg28JmE0JYVt56uo=" + }, + { + "content-length": "1155" + }, + { + "cache-control": "public, max-age=31067714" + }, + { + "expires": "Tue, 29 Oct 2013 02:46:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:54 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Fri, 31 Aug 2012 22:13:28 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "6/fKHkRtBpT4oqBg33tFHk2pO6SDZlUG11Uq4/AlUIE=" + }, + { + "content-length": "516" + }, + { + "cache-control": "public, max-age=26316304" + }, + { + "expires": "Wed, 04 Sep 2013 02:55:58 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:54 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "232" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Sat, 21 Apr 2012 07:03:57 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "XtTsONeGHGs/1vRRv8cvNY1ciB3XqlrvnTq2GZXvnqM=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=30419619" + }, + { + "expires": "Mon, 21 Oct 2013 14:44:35 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Fri, 07 Sep 2012 15:18:40 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "E2JBYTapyXFjxTTVqkrekTVKDp1lDQQT/7YxcxfNU2U=" + }, + { + "x-cnection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "400" + }, + { + "cache-control": "public, max-age=31066933" + }, + { + "expires": "Tue, 29 Oct 2013 02:33:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:41:45 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "iPbLdjapQzRoatbOUDrN+exDj8EPHJAcsZ48pVtprtA=" + }, + { + "content-length": "35766" + }, + { + "cache-control": "public, max-age=31068980" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:54 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Sun, 28 Oct 2012 14:34:50 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "0ci0R5R2ivIVCRrwtG507Eej+LTK8dUL8dIiZp70+dU=" + }, + { + "content-length": "10902" + }, + { + "cache-control": "public, max-age=31066965" + }, + { + "expires": "Tue, 29 Oct 2013 02:33:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:55 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:38:28 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "P2Bq0ebVXjtf8GyQp1HHux8NxlftUMXZuY8XF+yaOVo=" + }, + { + "content-length": "4676" + }, + { + "cache-control": "public, max-age=31088728" + }, + { + "expires": "Tue, 29 Oct 2013 08:36:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:37:10 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "yHzV/c0w3ZyInkRbLCDrA0t5adSMyAG4prBOk+i+t6Y=" + }, + { + "content-length": "20791" + }, + { + "cache-control": "public, max-age=31067654" + }, + { + "expires": "Tue, 29 Oct 2013 02:45:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "11113" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Sun, 28 Oct 2012 14:34:47 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "u363OvKFmnm717JBUXA5ePB8Ts0ppRI7+eEJwOOep6w=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=31066988" + }, + { + "expires": "Tue, 29 Oct 2013 02:34:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:02:57 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "Yty+Te4OzfswtmjzbJmJZaybyM0hxXiRU2NtHEbDuPE=" + }, + { + "content-length": "43" + }, + { + "cache-control": "public, max-age=25753573" + }, + { + "expires": "Wed, 28 Aug 2013 14:37:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:24 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "yKFyrxwqBiumMPfWvv4morUUsmz9djZtSdmCoQMnchs=" + }, + { + "content-length": "571" + }, + { + "cache-control": "public, max-age=25753811" + }, + { + "expires": "Wed, 28 Aug 2013 14:41:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "HbryxnP7HNa7kdTChA6BppSjLQw0gz9ZzESCqEH3/9k=" + }, + { + "content-length": "43" + }, + { + "cache-control": "public, max-age=25753770" + }, + { + "expires": "Wed, 28 Aug 2013 14:40:26 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Tue, 28 Aug 2012 01:20:00 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "edgqdu1lFmUW32Et2hHoiAsp9kFIch8QDiciO71cQ4w=" + }, + { + "content-length": "12817" + }, + { + "cache-control": "public, max-age=26458041" + }, + { + "expires": "Thu, 05 Sep 2013 18:18:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:09:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "rXXtxI3fPgNHe6wKIDRBR0xjttUNeG+BDQM8QfKQa+A=" + }, + { + "content-length": "11688" + }, + { + "cache-control": "public, max-age=31068990" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "35165" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:06:47 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "fUJ2Nc9qJdBC1AnYFA5Vs1f7ozv+i/PTKO+Vep0A0HQ=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=31068521" + }, + { + "expires": "Tue, 29 Oct 2013 02:59:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:07:00 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "s9ZmJKnYGlEjIGo8xQzxlhVM4nilGHgcv1fhK1Z7F1w=" + }, + { + "content-length": "1028" + }, + { + "cache-control": "public, max-age=31191849" + }, + { + "expires": "Wed, 30 Oct 2013 13:15:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:07:08 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "hMQvA7xhuAspt5fOxedr0fWzQZNLkyizVtlmspzgVG8=" + }, + { + "content-length": "47844" + }, + { + "cache-control": "public, max-age=31068990" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Mon, 29 Oct 2012 19:17:24 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "1EkJKYLfWucaDVhZCEVAAo57HpAH7rvF4r9IwDXM2B8=" + }, + { + "content-length": "42391" + }, + { + "cache-control": "public, max-age=31143832" + }, + { + "expires": "Tue, 29 Oct 2013 23:54:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "13181" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:10:32 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "dO6OKUf38jDdtAnTrM28wZTBz9Y5hU/0EJdd1CkWGDs=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=31068989" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:03:57 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "IlZ4dyc3v7fqrfiamqJbFeFTWRkUvEUs2L8KLXNa+5o=" + }, + { + "content-length": "23736" + }, + { + "cache-control": "public, max-age=31478360" + }, + { + "expires": "Sat, 02 Nov 2013 20:50:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:35:28 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "REVz0k4Gud7bedzv9KSTG2i1KOporb0T14mWht95MIE=" + }, + { + "content-length": "12969" + }, + { + "cache-control": "public, max-age=31394885" + }, + { + "expires": "Fri, 01 Nov 2013 21:39:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:06:44 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "VKvuYL/9rqvjXh7mr8LjSJmcgQLZ/a+Ztqj2aUsPacc=" + }, + { + "content-length": "8457" + }, + { + "cache-control": "public, max-age=31088728" + }, + { + "expires": "Tue, 29 Oct 2013 08:36:26 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":26,\"r\":18,\"q\":0,\"a\":30}" + }, + { + "x-fb-server": "10.164.86.49" + }, + { + "x-fb-debug": "egJridVr0Ohgw3QbFe66p8hTV/ZDa+ldtrrj55f1Dwg=" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "43" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":15,\"r\":74,\"q\":0,\"a\":21}" + }, + { + "x-fb-server": "10.164.212.85" + }, + { + "x-fb-debug": "7JVbUHGoJcLzIbHgkJPv0DSBycKYYPPorUc0i6OdRw8=" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "43" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":33,\"r\":14,\"q\":0,\"a\":27}" + }, + { + "x-fb-server": "10.164.203.85" + }, + { + "x-fb-debug": "SHFiC3r5rPZSoyQ6AT4o7Lrz58o2i0cRMRoLoKKAVLc=" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "10334" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":47,\"r\":27,\"q\":0,\"a\":24}" + }, + { + "x-fb-server": "10.164.121.55" + }, + { + "x-fb-debug": "B8TQ25HLrpUM+2nuhej+798G7ib2rXsLxKDRmmd6364=" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "79019" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "43" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:05 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "q1YlNQFhUrIi0HF88gF/s47itTMC0ALVS2i6Xo/eSFQ=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=17216856" + }, + { + "expires": "Tue, 21 May 2013 19:18:35 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:20 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "OOKrpYeJ1K2euVWUg0h3X4OLDU+bPXAhHe2ZbKmaIIo=" + }, + { + "content-length": "43" + }, + { + "cache-control": "public, max-age=17216855" + }, + { + "expires": "Tue, 21 May 2013 19:18:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:42:28 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "BWYgCEbzeWyERD5oPP51t1mG+xnS0km1r6TZrds9BdY=" + }, + { + "content-length": "55530" + }, + { + "cache-control": "public, max-age=31068989" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/png" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":47,\"r\":27,\"q\":0,\"a\":24}" + }, + { + "x-fb-server": "10.164.121.55" + }, + { + "x-fb-debug": "6DDnMStngO3Ec4qHVJLnouT/OjWIKWOh3p7X19lwA2E=" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "67" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "DY+dO6Fs6HOjJLzXfO2vzcoACugopwtj+ZfSFe3+0Io=" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Mon, 15 Oct 2012 01:19:28 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "U3t5ojZAXSlz/rftvVXMdi+dQaAlCxv95u4nFdmaOpU=" + }, + { + "content-length": "6332" + }, + { + "cache-control": "public, max-age=29865483" + }, + { + "expires": "Tue, 15 Oct 2013 04:49:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:19 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "WkN9kzT0IbJnmPVAe/JpiO1KA3sDm5JiLNu+peaU22E=" + }, + { + "content-length": "1025" + }, + { + "cache-control": "public, max-age=17216854" + }, + { + "expires": "Tue, 21 May 2013 19:18:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "7905" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:38:51 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "flUDwRXAcKGlCZV+B6xp1kix2zMM2jCaLr8GXWfOS9o=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=31191685" + }, + { + "expires": "Wed, 30 Oct 2013 13:12:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "960" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 07 Jun 2012 20:17:10 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "s2bSrOgSOrnc1I2Y+hCmZNjO4JKRAsJvvEShk7xvQh0=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=25753518" + }, + { + "expires": "Wed, 28 Aug 2013 14:36:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Fri, 13 Jul 2012 13:05:49 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "dSqFMj3BQam7KrjoHsDUySNYx2e/ZA4jk+iLwQD5q+M=" + }, + { + "content-length": "1421" + }, + { + "cache-control": "public, max-age=25753545" + }, + { + "expires": "Wed, 28 Aug 2013 14:36:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "3977" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:41:38 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "if1LyEGCEK6E/tHFIYqTdcReGf2YlH/8CNcvt0MSb5c=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=31162173" + }, + { + "expires": "Wed, 30 Oct 2013 05:00:35 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:03 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "0MQqsPt7SaQdEz9msJEk0wieC0zyyvfgvjy4gscfRm4=" + }, + { + "content-length": "316" + }, + { + "cache-control": "public, max-age=25628126" + }, + { + "expires": "Tue, 27 Aug 2013 03:46:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6779" + }, + { + "last-modified": "Wed, 09 May 2012 22:55:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7899" + }, + { + "last-modified": "Mon, 14 May 2012 09:15:54 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8961" + }, + { + "last-modified": "Fri, 10 Aug 2012 23:04:25 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7270" + }, + { + "last-modified": "Thu, 17 May 2012 17:02:26 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "10284" + }, + { + "last-modified": "Fri, 14 Sep 2012 13:43:01 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6932" + }, + { + "last-modified": "Tue, 15 May 2012 16:53:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "19404" + }, + { + "last-modified": "Fri, 13 Jul 2012 21:38:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":23,\"r\":24,\"q\":0,\"a\":31}" + }, + { + "x-fb-server": "10.164.204.89" + }, + { + "x-fb-debug": "mhzgPOTS+rD7XyjD1gp3zWldoiZpmeeyK0sWCXxCmL8=" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "43" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":13,\"r\":137,\"q\":0,\"a\":23}" + }, + { + "x-fb-server": "10.164.167.53" + }, + { + "x-fb-debug": "uWC6Yw5Jjt8tp6GMW/0c7q4sQiyN+cfsFumyrajMSLE=" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "43" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":20,\"r\":43,\"q\":0,\"a\":30}" + }, + { + "x-fb-server": "10.165.52.67" + }, + { + "x-fb-debug": "K6O9zzGnsjkFUcjVnvogKEp8WyYKDD5/1SRA3JOqTz8=" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "10334" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/jpeg" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":40,\"r\":33,\"q\":0,\"a\":22}" + }, + { + "x-fb-server": "10.164.10.79" + }, + { + "x-fb-debug": "gU+KRCRWrUp+aETSVFA2+QqzJ57Mry5y8i9NZISRzV4=" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "79019" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "content-type": "image/png" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-fb-metrics": "{\"w\":40,\"r\":33,\"q\":0,\"a\":22}" + }, + { + "x-fb-server": "10.164.10.79" + }, + { + "x-fb-debug": "2KYdrNd+vAjbaW2+l9lZ0c9qQnQQuLC0uV+aDWEfnEs=" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "67" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "ltZY31wZe0x9jjXZ+/GQMCIZ6L+UzLcVFaj4Ye8cEag=" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "32220" + }, + { + "last-modified": "Mon, 15 Oct 2012 15:37:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "105703" + }, + { + "last-modified": "Mon, 15 Oct 2012 15:38:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "36768" + }, + { + "last-modified": "Thu, 01 Nov 2012 01:55:42 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "119574" + }, + { + "last-modified": "Fri, 26 Oct 2012 09:41:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "659" + }, + { + "content-type": "image/x-icon" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "yE8mx2kOMcI8Q4MtoKCXYAXv7xSMQBGufoB0y/qkYEs=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=16309260" + }, + { + "expires": "Sat, 11 May 2013 07:12:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6966" + }, + { + "last-modified": "Thu, 17 May 2012 16:26:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4501" + }, + { + "last-modified": "Fri, 06 Jul 2012 11:36:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "37432" + }, + { + "last-modified": "Mon, 04 Jun 2012 08:35:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7198" + }, + { + "last-modified": "Tue, 15 May 2012 16:45:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "13454" + }, + { + "last-modified": "Thu, 31 May 2012 01:48:38 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "application/json" + }, + { + "access-control-allow-origin": "http://www.facebook.com" + }, + { + "access-control-allow-credentials": "true" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0" + }, + { + "pragma": "no-cache" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 12:51:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "19537" + }, + { + "last-modified": "Tue, 19 Jun 2012 08:51:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5842" + }, + { + "last-modified": "Mon, 14 May 2012 22:03:47 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6973" + }, + { + "last-modified": "Tue, 22 May 2012 23:26:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7263" + }, + { + "last-modified": "Mon, 11 Jun 2012 21:11:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6222" + }, + { + "last-modified": "Tue, 15 May 2012 02:10:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8005" + }, + { + "last-modified": "Fri, 13 Jul 2012 02:50:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7949" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:25:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5850" + }, + { + "last-modified": "Wed, 23 May 2012 13:04:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4860" + }, + { + "last-modified": "Fri, 18 May 2012 06:59:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "36615" + }, + { + "last-modified": "Fri, 08 Jun 2012 09:18:35 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "26180" + }, + { + "last-modified": "Fri, 01 Jun 2012 12:58:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8551" + }, + { + "last-modified": "Wed, 16 May 2012 00:19:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7021" + }, + { + "last-modified": "Fri, 18 May 2012 08:58:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8126" + }, + { + "last-modified": "Thu, 17 May 2012 10:31:00 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "21780" + }, + { + "last-modified": "Fri, 20 Jul 2012 20:43:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "16109" + }, + { + "last-modified": "Fri, 08 Jun 2012 21:45:00 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5248" + }, + { + "last-modified": "Tue, 15 May 2012 17:19:22 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7600" + }, + { + "last-modified": "Tue, 15 May 2012 00:02:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8148" + }, + { + "last-modified": "Tue, 04 Sep 2012 05:25:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "23688" + }, + { + "last-modified": "Tue, 05 Jun 2012 16:58:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "32579" + }, + { + "last-modified": "Fri, 15 Jun 2012 23:21:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "36154" + }, + { + "last-modified": "Tue, 15 May 2012 16:53:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8261" + }, + { + "last-modified": "Thu, 17 May 2012 16:15:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "34603" + }, + { + "last-modified": "Tue, 05 Jun 2012 19:33:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1209600" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "19320" + }, + { + "last-modified": "Fri, 20 Jul 2012 22:33:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:59:56 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "cEr4CpqyPlutZEM5egM7EW1V/FoNLas8puqhILOyn6g=" + }, + { + "content-length": "1589" + }, + { + "cache-control": "public, max-age=31191410" + }, + { + "expires": "Wed, 30 Oct 2013 13:08:05 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:34 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "SjbWzWIhc5uDeUgKzkah4oVawEfOfsqgn79tJvLiODA=" + }, + { + "content-length": "124" + }, + { + "cache-control": "public, max-age=25632795" + }, + { + "expires": "Tue, 27 Aug 2013 05:04:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:02:59 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "8BYYADIiLWZPRqrmghOTJnnu5b75InjLJYums29XQC4=" + }, + { + "content-length": "178" + }, + { + "cache-control": "public, max-age=25638838" + }, + { + "expires": "Tue, 27 Aug 2013 06:45:13 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Fri, 26 Oct 2012 21:42:07 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "rg/3x10ePyW5+Yv14okaeMgQpdIDitUpRdeQlHd62wU=" + }, + { + "content-length": "3403" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "public, max-age=31099667" + }, + { + "expires": "Tue, 29 Oct 2013 11:39:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:11:34 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "+G0d7Y1/nAK76h5l1ygZcgFyqkHdYYjzu9bN8TThTW0=" + }, + { + "content-length": "3794" + }, + { + "cache-control": "public, max-age=31090886" + }, + { + "expires": "Tue, 29 Oct 2013 09:12:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:16 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Thu, 27 Sep 2012 22:19:28 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "Zx9+0hICgorbmj40+TVQqx/6DWk0JFijw5sOouOK4x8=" + }, + { + "content-length": "4316" + }, + { + "cache-control": "public, max-age=31191442" + }, + { + "expires": "Wed, 30 Oct 2013 13:08:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:16 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:02:59 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "y9gp03qLmGwdrjrggsFyxKUnduRuH6ZkhHy3J217wnA=" + }, + { + "content-length": "82" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "public, max-age=25628121" + }, + { + "expires": "Tue, 27 Aug 2013 03:46:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:15 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "y31IzOtXz6QEqDb4Yh8nL9E7Jz3QdrtFTVTfJpFI67s=" + }, + { + "content-length": "281" + }, + { + "cache-control": "public, max-age=25628127" + }, + { + "expires": "Tue, 27 Aug 2013 03:46:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:16 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:07:48 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "cdKo7nf6SbFgEUsu8p8ZpYkyd14IkSsYwu8pEpjIPW8=" + }, + { + "content-length": "18581" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "public, max-age=31068960" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:28:22 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "Mcoj0fymAm3BWRvLoE9uVgrJkXk8Wldn9hUKly6PE60=" + }, + { + "content-length": "686" + }, + { + "cache-control": "public, max-age=31067324" + }, + { + "expires": "Tue, 29 Oct 2013 02:40:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "70824" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Sun, 28 Oct 2012 14:35:10 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "U6CnJQe7lFM5/wvYBRcEyvixo284qs3dxFI4vIJ3Sfo=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=31117935" + }, + { + "expires": "Tue, 29 Oct 2013 16:43:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "6953" + }, + { + "content-type": "application/x-shockwave-flash" + }, + { + "last-modified": "Mon, 29 Oct 2012 18:56:50 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "8ROXKJ/K5IoNZG3RcJoN8LoohKyoDW2iTe6nY9hRINI=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=260332" + }, + { + "expires": "Tue, 06 Nov 2012 13:10:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:20 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "6953" + }, + { + "content-type": "application/x-shockwave-flash" + }, + { + "last-modified": "Mon, 29 Oct 2012 18:56:50 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "8ROXKJ/K5IoNZG3RcJoN8LoohKyoDW2iTe6nY9hRINI=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=260331" + }, + { + "expires": "Tue, 06 Nov 2012 13:10:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:21 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Tue, 30 Oct 2012 17:45:29 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-debug": "casrvtlqM38DGgUK+sC64wYFWqXchCM2wnMjgM8VC98=" + }, + { + "content-length": "15685" + }, + { + "cache-control": "public, max-age=31299110" + }, + { + "expires": "Thu, 31 Oct 2013 19:03:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:20 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "1591" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "last-modified": "Thu, 20 Sep 2012 01:12:35 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "E9XqLqcAPtaMWK+vlxTTyhNPMewUq9nSCKax+m9KMwk=" + }, + { + "x-cnection": "close" + }, + { + "cache-control": "public, max-age=28776235" + }, + { + "expires": "Wed, 02 Oct 2013 14:15:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 12:51:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_27.json b/jetty-http2/http2-hpack/src/test/resources/data/story_27.json new file mode 100644 index 00000000000..0a0077dcd2c --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_27.json @@ -0,0 +1,9890 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:41:12 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:12 GMT; path=/; domain=.flickr.com" + }, + { + "location": "http://www.flickr.com/" + }, + { + "cache-control": "private" + }, + { + "x-served-by": "www199.flickr.mud.yahoo.com" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "20" + }, + { + "connection": "close" + }, + { + "content-type": "text/html; charset=UTF-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:13 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:05:01 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www199.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "no-store, no-cache, must-revalidate, max-age=0" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "0" + }, + { + "via": "HTTP/1.1 r16.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:15 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "private, no-store, max-age=0" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Wed, 31 Oct 2012 09:50:22 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www25.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "max-age=315360000" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/png" + }, + { + "age": "273053" + }, + { + "via": "HTTP/1.1 r42.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "35102" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Thu, 01 Nov 2012 04:23:38 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Tue, 06 Mar 2012 23:48:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "21830" + }, + { + "x-served-by": "www145.flickr.mud.yahoo.com" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "cache-control": "max-age=315360000" + }, + { + "content-type": "image/png" + }, + { + "age": "206257" + }, + { + "via": "HTTP/1.1 r46.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ]), HTTP/1.1 r9.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:15 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www187.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "age": "0" + }, + { + "via": "HTTP/1.1 r44.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "35102" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:15 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:16 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 355 dc10_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:17 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "327" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:28:23 GMT" + }, + { + "p3p": "policyref=\"http://p3p.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV\"" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:00:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding,User-Agent" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=3600" + }, + { + "content-type": "text/plain; charset=utf-8" + }, + { + "age": "773" + }, + { + "content-length": "111260" + }, + { + "connection": "keep-alive" + }, + { + "server": "ATS/3.2.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:16 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:19 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www18.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "0" + }, + { + "via": "HTTP/1.1 r48.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "35102" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "fldetectedlang=en-us; expires=Wed, 02-Jan-2013 13:41:19 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5002" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:30:08 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:33 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "45842" + }, + { + "x-cache": "HIT from photocache510.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache510.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache510.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2849" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:51:39 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "88063" + }, + { + "x-cache": "HIT from photocache540.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache540.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache540.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3533" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Thu, 27 Oct 2022 22:31:31 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "609449" + }, + { + "x-cache": "HIT from photocache530.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache530.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache530.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8165" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 03 Jul 2022 07:34:11 UTC" + }, + { + "last-modified": "Tue, 10 Nov 2009 20:15:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "1332" + }, + { + "x-cache": "HIT from photocache324.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache324.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache324.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "16040" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:51:39 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:32 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "104768" + }, + { + "x-cache": "HIT from photocache518.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache518.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache518.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "16818" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:51:39 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "104768" + }, + { + "x-cache": "HIT from photocache530.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache530.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache530.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "258838" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 09:14:20 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "3930" + }, + { + "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "15513" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 09:47:34 UTC" + }, + { + "last-modified": "Mon, 06 Jun 2011 11:22:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "9645" + }, + { + "x-cache": "HIT from photocache502.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache502.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache502.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:20 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 380 dc11_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:21 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:21 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7878" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Wed, 20 Jul 2022 12:23:18 UTC" + }, + { + "last-modified": "Mon, 23 Jun 2008 19:15:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "41746" + }, + { + "x-cache": "HIT from photocache114.flickr.mud.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache114.flickr.mud.yahoo.com:83" + }, + { + "via": "1.1 photocache114.flickr.mud.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:21 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:21 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3339" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sat, 01 Oct 2022 14:49:54 UTC" + }, + { + "last-modified": "Mon, 01 Oct 2012 03:50:32 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "79702" + }, + { + "x-cache": "HIT from photocache902.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache902.flickr.bf1.yahoo.com:83" + }, + { + "via": "1.1 photocache902.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:21 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www145.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/javascript; charset=utf-8" + }, + { + "age": "0" + }, + { + "via": "HTTP/1.1 r02.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "35102" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "fldetectedlang=en-us; expires=Wed, 02-Jan-2013 13:41:19 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3403" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:01:02 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:47 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "146624" + }, + { + "x-cache": "HIT from photocache538.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache538.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache538.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3018" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:35:06 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "498650" + }, + { + "x-cache": "HIT from photocache509.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache509.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache509.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3493" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:01:02 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "184716" + }, + { + "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "19066" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:35:06 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "498650" + }, + { + "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "14587" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:35:06 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:44:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "498650" + }, + { + "x-cache": "HIT from photocache512.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache512.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache512.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "16541" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 09:51:39 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:55 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "64145" + }, + { + "x-cache": "HIT from photocache538.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache538.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache538.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "17669" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:35:06 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "498070" + }, + { + "x-cache": "HIT from photocache536.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache536.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache536.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "17009" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:35:06 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "498070" + }, + { + "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "110090" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 09:50:49 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "104763" + }, + { + "x-cache": "HIT from photocache508.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache508.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache508.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:22 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "121145" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 09:14:22 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "104763" + }, + { + "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:23 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www105.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "0" + }, + { + "via": "HTTP/1.1 r08.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "35102" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:23 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:24 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 328 dc26_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:25 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:24 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5372" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 24 Jul 2022 05:03:05 UTC" + }, + { + "last-modified": "Sat, 10 Jul 2010 18:58:01 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "113797" + }, + { + "x-cache": "HIT from photocache417.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache417.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache417.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:24 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:25 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "101072" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 09:13:50 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:33 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "399124" + }, + { + "x-cache": "HIT from photocache502.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache502.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache502.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:25 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www135.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "3" + }, + { + "via": "HTTP/1.1 r34.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "35102" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:25 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:26 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 358 dc28_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:27 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:26 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:26 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:27 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:27 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "131822" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 09:13:19 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "399125" + }, + { + "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:27 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www198.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "3" + }, + { + "via": "HTTP/1.1 r34.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "35102" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:27 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:28 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 366 dc36_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:29 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:29 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:29 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "137767" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 09:13:04 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "959688" + }, + { + "x-cache": "HIT from photocache512.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache512.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache512.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www24.flickr.bf1.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "1" + }, + { + "via": "HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "35102" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:30 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "9755" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:27:41 UTC" + }, + { + "last-modified": "Mon, 04 Oct 2010 23:11:18 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "783768" + }, + { + "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "8018" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:27:41 UTC" + }, + { + "last-modified": "Mon, 04 Oct 2010 23:11:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "783767" + }, + { + "x-cache": "HIT from photocache521.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache521.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache521.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5509" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:27:41 UTC" + }, + { + "last-modified": "Mon, 04 Oct 2010 23:11:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "849721" + }, + { + "x-cache": "HIT from photocache517.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache517.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache517.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "24244" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:27:41 UTC" + }, + { + "last-modified": "Mon, 04 Oct 2010 23:11:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "832233" + }, + { + "x-cache": "HIT from photocache503.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache503.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache503.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "15699" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:49:46 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:54 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "184724" + }, + { + "x-cache": "HIT from photocache535.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache535.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache535.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "26051" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:27:41 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 19:06:02 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "783767" + }, + { + "x-cache": "HIT from photocache501.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache501.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache501.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "13263" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:08 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "216108" + }, + { + "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "19324" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 03 Jul 2022 22:23:27 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301732" + }, + { + "x-cache": "HIT from photocache539.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache539.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache539.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "21573" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:27:42 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:47 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "14644" + }, + { + "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "20730" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:27:42 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:44:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301890" + }, + { + "x-cache": "HIT from photocache528.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache528.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache528.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "32916" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:08 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "251785" + }, + { + "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "26574" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:27:42 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:55 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "832232" + }, + { + "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "27759" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 22:06:23 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301883" + }, + { + "x-cache": "HIT from photocache528.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache528.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache528.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "11409" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:10 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "832232" + }, + { + "x-cache": "HIT from photocache524.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache524.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache524.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "26453" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 24 Jul 2022 04:56:22 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:33 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "3058" + }, + { + "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "23128" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 22:06:23 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:33 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301877" + }, + { + "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "28275" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 22:06:23 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301881" + }, + { + "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:30 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "26267" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 22:06:23 UTC" + }, + { + "last-modified": "Wed, 15 Sep 2010 19:43:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301876" + }, + { + "x-cache": "HIT from photocache514.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache514.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache514.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:31 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 369 dc23_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:32 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:31 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:31 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:31 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Wed, 31 Oct 2012 09:31:12 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www96.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "max-age=1209600" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/vnd.microsoft.icon" + }, + { + "age": "274220" + }, + { + "via": "HTTP/1.1 r15.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "6640" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:30 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:33 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www1.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "0" + }, + { + "via": "HTTP/1.1 r12.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "6640" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:33 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "19144" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:09 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301872" + }, + { + "x-cache": "HIT from photocache508.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache508.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache508.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "24110" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:09 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "840419" + }, + { + "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "32406" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 18:43:07 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "166451" + }, + { + "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "20059" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:09 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "382867" + }, + { + "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "23332" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:41:55 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "68360" + }, + { + "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "18543" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:24:48 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "458533" + }, + { + "x-cache": "HIT from photocache538.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache538.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache538.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "15399" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 30 Oct 2022 01:48:16 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:47:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "424858" + }, + { + "x-cache": "HIT from photocache324.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache324.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache324.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "29793" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Tue, 16 Aug 2022 22:34:17 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 22:00:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "840419" + }, + { + "x-cache": "HIT from photocache401.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache401.flickr.ac4.yahoo.com:81" + }, + { + "via": "1.1 photocache401.flickr.ac4.yahoo.com:81 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "13571" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:16:36 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "783188" + }, + { + "x-cache": "HIT from photocache508.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache508.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache508.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "18149" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 12 Jun 2022 23:12:34 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 21:59:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "953364" + }, + { + "x-cache": "HIT from photocache414.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache414.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache414.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "15403" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:09 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "388250" + }, + { + "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "14796" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 22:06:24 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 21:59:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "320180" + }, + { + "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "18710" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:09 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:24 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "840419" + }, + { + "x-cache": "HIT from photocache531.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache531.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache531.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "32555" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 19 Jun 2022 15:01:08 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 22:00:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "58741" + }, + { + "x-cache": "HIT from photocache412.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache412.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache412.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "13726" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:10 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 21:59:24 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "840419" + }, + { + "x-cache": "HIT from photocache531.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache531.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache531.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "27660" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 22:06:36 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 21:59:47 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "320180" + }, + { + "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "19545" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:38:09 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 21:59:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "840419" + }, + { + "x-cache": "HIT from photocache517.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache517.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache517.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "30518" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 16:28:03 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:47:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "49685" + }, + { + "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:34 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 310 dc33_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:35 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:35 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:38 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 342 dc32_ne1" + }, + { + "connection": "close" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:39 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "site tracked" + }, + { + "content-length": "43" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:39 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www31.flickr.bf1.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "3" + }, + { + "via": "HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "6640" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:39 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:40 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "private, no-store, max-age=0" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:41 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 352 dc19_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:42 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "imp=a$le#1351950101610_669834368_ap2101_int|; Domain=.teracent.net; Expires=Thu, 02-May-2013 13:41:41 GMT; Path=/tase" + }, + { + "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "expires": "Sat, 6 May 1995 12:00:00 GMT" + }, + { + "cache-control": "post-check=0, pre-check=0" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:41:41 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:41 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www56.flickr.bf1.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "0" + }, + { + "via": "HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "6640" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:44 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2830" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 07:50:16 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "4009" + }, + { + "x-cache": "HIT from photocache501.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache501.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache501.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4884" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 07:44:25 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "159147" + }, + { + "x-cache": "HIT from photocache520.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache520.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache520.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3513" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 07:49:35 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:18 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "4010" + }, + { + "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6899" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 07:49:08 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:22 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "2328198" + }, + { + "x-cache": "HIT from photocache518.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache518.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache518.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4695" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Thu, 03 Nov 2022 23:49:24 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "MISS from photocache514.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "MISS from photocache514.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache514.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2596" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 07:55:46 UTC" + }, + { + "last-modified": "Mon, 04 Oct 2010 23:11:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431512" + }, + { + "x-cache": "HIT from photocache518.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache518.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache518.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3516" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 17:53:36 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "302049" + }, + { + "x-cache": "HIT from photocache501.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache501.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache501.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4922" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:47 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "36944" + }, + { + "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3158" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 07:46:15 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "2328157" + }, + { + "x-cache": "HIT from photocache512.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache512.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache512.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4541" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:12 UTC" + }, + { + "last-modified": "Thu, 16 Sep 2010 17:19:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "302053" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4145" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 07:51:21 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:40:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "2328231" + }, + { + "x-cache": "HIT from photocache508.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache508.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache508.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3419" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:06:37 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "650868" + }, + { + "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5035" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 20:41:31 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:02 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "3999" + }, + { + "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:44 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "private, no-store, max-age=0" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 305 dc9_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:46 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "45" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5313" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Thu, 01 Sep 2022 04:55:06 UTC" + }, + { + "last-modified": "Fri, 31 Aug 2012 18:28:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "959613" + }, + { + "x-cache": "HIT from photocache906.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache906.flickr.bf1.yahoo.com:83" + }, + { + "via": "1.1 photocache906.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4675" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Wed, 07 Sep 2022 05:56:52 UTC" + }, + { + "last-modified": "Thu, 06 Sep 2012 18:42:55 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "338945" + }, + { + "x-cache": "HIT from photocache907.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache907.flickr.bf1.yahoo.com:83" + }, + { + "via": "1.1 photocache907.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7282" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 28 Aug 2022 09:31:01 UTC" + }, + { + "last-modified": "Mon, 27 Aug 2012 22:28:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "73654" + }, + { + "x-cache": "HIT from photocache924.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache924.flickr.bf1.yahoo.com:85" + }, + { + "via": "1.1 photocache924.flickr.bf1.yahoo.com:85 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4242" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Thu, 01 Sep 2022 04:55:06 UTC" + }, + { + "last-modified": "Fri, 31 Aug 2012 18:28:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "959613" + }, + { + "x-cache": "HIT from photocache926.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache926.flickr.bf1.yahoo.com:83" + }, + { + "via": "1.1 photocache926.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4561" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 17 Jul 2022 03:19:16 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "4005" + }, + { + "x-cache": "HIT from photocache203.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache203.flickr.bf1.yahoo.com:83" + }, + { + "via": "1.1 photocache203.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6350" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 17 Jul 2022 04:55:35 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 16:18:41 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431728" + }, + { + "x-cache": "HIT from photocache204.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache204.flickr.bf1.yahoo.com:83" + }, + { + "via": "1.1 photocache204.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3341" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 17 Jul 2022 18:09:37 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "2328215" + }, + { + "x-cache": "HIT from photocache205.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache205.flickr.bf1.yahoo.com:85" + }, + { + "via": "1.1 photocache205.flickr.bf1.yahoo.com:85 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7005" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 18 Jul 2022 01:41:12 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "4064" + }, + { + "x-cache": "HIT from photocache202.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache202.flickr.bf1.yahoo.com:85" + }, + { + "via": "1.1 photocache202.flickr.bf1.yahoo.com:85 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4068" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 18 Jul 2022 03:45:04 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:01 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "438025" + }, + { + "x-cache": "HIT from photocache202.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache202.flickr.bf1.yahoo.com:83" + }, + { + "via": "1.1 photocache202.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7960" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 18 Jul 2022 03:44:32 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:41:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "2328207" + }, + { + "x-cache": "HIT from photocache205.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache205.flickr.bf1.yahoo.com:85" + }, + { + "via": "1.1 photocache205.flickr.bf1.yahoo.com:85 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:45 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:46 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4395" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 18 Jul 2022 03:45:05 UTC" + }, + { + "last-modified": "Mon, 01 Nov 2010 05:40:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "2328241" + }, + { + "x-cache": "HIT from photocache202.flickr.bf1.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache202.flickr.bf1.yahoo.com:83" + }, + { + "via": "1.1 photocache202.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:48 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www30.flickr.bf1.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "3" + }, + { + "via": "HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "6640" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:48 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3706" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 21:59:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "608527" + }, + { + "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4610" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 16:47:58 UTC" + }, + { + "last-modified": "Wed, 04 Aug 2010 23:21:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "598783" + }, + { + "x-cache": "HIT from photocache515.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache515.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache515.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2551" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:12 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "801137" + }, + { + "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2822" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:43:25 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache504.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache504.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache504.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "151390" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4463" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:56:37 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "252496" + }, + { + "x-cache": "HIT from photocache520.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache520.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache520.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1441" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:25 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "496025" + }, + { + "x-cache": "HIT from photocache501.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache501.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache501.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3780" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sat, 22 Oct 2022 00:35:44 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:47:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "988214" + }, + { + "x-cache": "HIT from photocache312.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache312.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache312.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5215" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 24 Oct 2022 02:15:29 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:47:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431732" + }, + { + "x-cache": "HIT from photocache324.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache324.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache324.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2610" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:49:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "872080" + }, + { + "x-cache": "HIT from photocache520.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache520.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache520.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4241" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 08:00:12 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:47:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "2356" + }, + { + "x-cache": "HIT from photocache513.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache513.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache513.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4461" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:10:07 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301869" + }, + { + "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4292" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 13:51:59 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "258540" + }, + { + "x-cache": "HIT from photocache521.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache521.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache521.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3353" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:49:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache518.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache518.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache518.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "496025" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4008" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 20:42:08 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "435217" + }, + { + "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4081" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:43:52 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "435217" + }, + { + "x-cache": "HIT from photocache521.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache521.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache521.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3996" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 15:30:11 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:46:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "872288" + }, + { + "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2178" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 20:42:08 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:44 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431529" + }, + { + "x-cache": "HIT from photocache523.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache523.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache523.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3292" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:39:41 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431732" + }, + { + "x-cache": "HIT from photocache533.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache533.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache533.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3415" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "89675" + }, + { + "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3963" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 15:19:56 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:59:09 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache533.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache533.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache533.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "89675" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3036" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Wed, 04 Aug 2010 23:21:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "245531" + }, + { + "x-cache": "HIT from photocache511.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache511.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache511.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1843" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431517" + }, + { + "x-cache": "HIT from photocache537.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache537.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache537.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6971" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301877" + }, + { + "x-cache": "HIT from photocache537.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache537.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache537.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3968" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:49:02 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431731" + }, + { + "x-cache": "HIT from photocache527.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache527.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache527.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:49 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "private, no-store, max-age=0" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:50 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 326 dc12_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:51 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:50 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:41:50 GMT" + }, + { + "server": "YTS/1.20.13" + }, + { + "x-rightmedia-hostname": "raptor0740.rm.bf1.yahoo.com" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\"" + }, + { + "location": "http://ad.yieldmanager.com/pixel?id=365081&t=2" + }, + { + "cache-control": "no-cache, no-store, must-revalidate, max-age=0" + }, + { + "vary": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:41:50 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:50 GMT" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4726" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 17:54:01 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:36 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "211089" + }, + { + "x-cache": "HIT from photocache519.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache519.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache519.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4433" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 04 Jul 2022 00:08:57 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:49:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431736" + }, + { + "x-cache": "HIT from photocache539.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache539.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache539.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2677" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:49:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431735" + }, + { + "x-cache": "HIT from photocache524.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache524.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache524.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3081" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:54 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "164867" + }, + { + "x-cache": "HIT from photocache511.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache511.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache511.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3457" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "435221" + }, + { + "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4433" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:12 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:42 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "424621" + }, + { + "x-cache": "HIT from photocache528.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache528.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache528.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "6486" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:46:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431736" + }, + { + "x-cache": "HIT from photocache540.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache540.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache540.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4899" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:12 UTC" + }, + { + "last-modified": "Wed, 04 Aug 2010 23:21:41 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "598778" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3981" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sat, 15 Oct 2022 23:23:06 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:46:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431687" + }, + { + "x-cache": "HIT from photocache311.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache311.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache311.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7338" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sun, 12 Jun 2022 22:06:49 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 22:00:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "608533" + }, + { + "x-cache": "HIT from photocache415.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache415.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache415.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5640" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:48:36 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:47:01 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "988205" + }, + { + "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4609" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:24 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "871819" + }, + { + "x-cache": "HIT from photocache530.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache530.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache530.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3776" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:39:41 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431533" + }, + { + "x-cache": "HIT from photocache531.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache531.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache531.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4551" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:35:21 UTC" + }, + { + "last-modified": "Tue, 17 Aug 2010 18:40:02 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "415587" + }, + { + "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4452" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 20:41:31 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:44 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "36952" + }, + { + "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2023" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 20:45:55 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache533.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache533.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache533.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "682487" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:51 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www144.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "3" + }, + { + "via": "HTTP/1.1 r29.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "6640" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:51 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4675" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:44:19 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:59:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "89679" + }, + { + "x-cache": "HIT from photocache502.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache502.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache502.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3139" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:09:56 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:59:00 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "89670" + }, + { + "x-cache": "HIT from photocache531.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache531.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache531.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3167" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:12 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:26 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431533" + }, + { + "x-cache": "HIT from photocache515.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache515.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache515.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4227" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:25 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "89679" + }, + { + "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2768" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 11:43:02 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:09 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "206489" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4375" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 21:59:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "988235" + }, + { + "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3506" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 18:52:47 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:36 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431534" + }, + { + "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3522" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 21:59:24 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "988233" + }, + { + "x-cache": "HIT from photocache515.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache515.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache515.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:53 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "private, no-store, max-age=0" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 307 dc1_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:55 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "45" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "server": "YTS/1.20.13" + }, + { + "x-rightmedia-hostname": "raptor0291.rm.bf1.yahoo.com" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\"" + }, + { + "cache-control": "no-cache, no-store, must-revalidate, max-age=0" + }, + { + "vary": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "server": "YTS/1.20.13" + }, + { + "x-rightmedia-hostname": "raptor0921.rm.bf1.yahoo.com" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\"" + }, + { + "cache-control": "no-cache, no-store, must-revalidate, max-age=0" + }, + { + "vary": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:54 GMT" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "location": "http://ad.yieldmanager.com/imp?Z=1x1&s=768714&T=3&_salt=2374354217&B=12&m=2&u=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Fnasacommons%2Ftags%2Fnationalaeronauticsandspaceadministration%2Fpage3%2F&r=0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:55 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "x-served-by": "www13.flickr.mud.yahoo.com" + }, + { + "x-flickr-static": "1" + }, + { + "cache-control": "private" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "age": "0" + }, + { + "via": "HTTP/1.1 r18.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])" + }, + { + "server": "YTS/1.20.20" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-length": "6640" + }, + { + "expires": "Mon, 28 Jul 2014 23:30:00 GMT" + }, + { + "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:55 GMT; path=/; domain=.flickr.com" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5525" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:39:41 UTC" + }, + { + "last-modified": "Wed, 04 Aug 2010 23:21:42 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "435224" + }, + { + "x-cache": "HIT from photocache503.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache503.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache503.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4651" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:21:30 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:59:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "166264" + }, + { + "x-cache": "HIT from photocache524.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache524.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache524.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4344" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:43:52 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301880" + }, + { + "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4372" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:35 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431536" + }, + { + "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4446" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:44 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431689" + }, + { + "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4431" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:46:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache511.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache511.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache511.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "431690" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "13813" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Sat, 03 Sep 2022 23:41:41 UTC" + }, + { + "last-modified": "Mon, 17 May 2010 22:00:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "608533" + }, + { + "x-cache": "HIT from photocache408.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache408.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache408.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2010" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:43:52 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431537" + }, + { + "x-cache": "HIT from photocache535.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache535.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache535.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4596" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:24 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "301900" + }, + { + "x-cache": "HIT from photocache540.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache540.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache540.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4383" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:25 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache540.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache540.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache540.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "89682" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3501" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 08:02:11 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:59:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "89673" + }, + { + "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3829" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:11 UTC" + }, + { + "last-modified": "Wed, 04 Aug 2010 23:21:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "871646" + }, + { + "x-cache": "HIT from photocache523.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache523.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache523.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3781" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 20:46:07 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:49:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "435223" + }, + { + "x-cache": "HIT from photocache502.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache502.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache502.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4186" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 20:41:31 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "363909" + }, + { + "x-cache": "HIT from photocache524.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache524.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache524.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3814" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:43:52 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:59:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache537.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache537.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache537.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "89682" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2478" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:25 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431536" + }, + { + "x-cache": "HIT from photocache511.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache511.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache511.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "7387" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Wed, 31 Mar 2010 17:47:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431739" + }, + { + "x-cache": "HIT from photocache523.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache523.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache523.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5870" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:04:10 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "337938" + }, + { + "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "5202" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:40:12 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:57:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431738" + }, + { + "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2820" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "431536" + }, + { + "x-cache": "HIT from photocache538.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache538.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache538.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3044" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:43:52 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:07:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "x-cache": "HIT from photocache516.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache516.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache516.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + }, + { + "age": "2363" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "4834" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 12:34:28 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:59:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "89682" + }, + { + "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3365" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:56:07 UTC" + }, + { + "last-modified": "Tue, 03 Aug 2010 22:58:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "252421" + }, + { + "x-cache": "HIT from photocache528.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache528.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache528.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "3978" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "max-age=315360000,public" + }, + { + "expires": "Mon, 30 May 2022 10:39:41 UTC" + }, + { + "last-modified": "Mon, 30 Aug 2010 06:49:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "age": "872078" + }, + { + "x-cache": "HIT from photocache532.flickr.ac4.yahoo.com" + }, + { + "x-cache-lookup": "HIT from photocache532.flickr.ac4.yahoo.com:83" + }, + { + "via": "1.1 photocache532.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:56 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "private, no-store, max-age=0" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:57 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com" + }, + { + "ts": "0 372 dc33_ne1" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:58 GMT" + }, + { + "cache-control": "no-cache, private, must-revalidate" + }, + { + "content-length": "46" + }, + { + "accept-ranges": "bytes" + }, + { + "tracking-status": "fpc site tracked" + }, + { + "vary": "Accept-Encoding" + }, + { + "connection": "close" + }, + { + "content-type": "application/x-javascript" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:41:57 GMT" + }, + { + "server": "YTS/1.20.13" + }, + { + "x-rightmedia-hostname": "raptor0663.rm.bf1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\"" + }, + { + "location": "http://ad.yieldmanager.com/pixel?id=372009&t=2" + }, + { + "cache-control": "no-cache, no-store, must-revalidate, max-age=0" + }, + { + "vary": "*" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:41:57 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:57 GMT" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:57 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:57 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:57 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:41:58 GMT" + }, + { + "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"" + }, + { + "cache-control": "no-cache, no-store, private" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_28.json b/jetty-http2/http2-hpack/src/test/resources/data/story_28.json new file mode 100644 index 00000000000..26c5a59aded --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_28.json @@ -0,0 +1,5293 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "301" + }, + { + "location": "http://www.linkedin.com/" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:13:39 GMT" + }, + { + "server": "lighttpd" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "X-LI-IDC=C1" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "E2zvmRmjhYEFJpx7GePGrg==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:13:39 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Tue, 30 Oct 2012 22:43:31 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4224" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31224822" + }, + { + "expires": "Wed, 30 Oct 2013 22:47:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "1757" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=23972673" + }, + { + "expires": "Thu, 08 Aug 2013 00:18:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Mon, 29 Oct 2012 17:17:34 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "1104" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31119071" + }, + { + "expires": "Tue, 29 Oct 2013 17:24:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Tue, 30 Oct 2012 22:43:30 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4725" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31225090" + }, + { + "expires": "Wed, 30 Oct 2013 22:51:51 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Tue, 30 Oct 2012 22:43:29 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "18531" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31225288" + }, + { + "expires": "Wed, 30 Oct 2013 22:55:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Tue, 30 Oct 2012 22:43:30 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-li-uuid": "YP+9O9z6wRIwf5dQLCsAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "81464" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31224801" + }, + { + "expires": "Wed, 30 Oct 2013 22:47:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "L1e=495eba97; path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "gLtcwO0VwxJQ3EsqHysAAA==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "image/gif" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:13:43 GMT" + }, + { + "age": "1" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Thu, 25 Oct 2012 19:08:05 GMT" + }, + { + "content-type": "image/x-icon" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-li-uuid": "YP+9O9z6wRIwf5dQLCsAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "361" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31188041" + }, + { + "expires": "Wed, 30 Oct 2013 12:34:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Wed, 31 Oct 2012 19:11:14 GMT" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-li-uuid": "CCdnnfDTwhJwlNCV9ioAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=31463444" + }, + { + "expires": "Sat, 02 Nov 2013 17:04:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:44 GMT" + }, + { + "content-length": "3489" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Mon, 13 Aug 2012 19:03:38 GMT" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1062" + }, + { + "cache-control": "max-age=24472323" + }, + { + "expires": "Tue, 13 Aug 2013 19:05:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:13:44 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "14888" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 22 Oct 2012 15:51:19 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Sat, 03 Nov 2012 06:13:29 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 18:13:29 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "25215" + }, + { + "cache-control": "max-age=43200, public" + }, + { + "server": "GFE/2.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "35" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "168216" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "server": "GFE/2.0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "content-length": "35" + }, + { + "x-content-type-options": "nosniff" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "age": "168216" + }, + { + "server": "GFE/2.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 03-Nov-2012 13:13:45 GMT" + }, + { + "etag": "M0-0eb75f26" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, no-transform, must-revalidate, max-age=604800" + }, + { + "expires": "Sat, 10 Nov 2012 13:13:45 GMT" + }, + { + "content-length": "2298" + }, + { + "date": "Sat, 03 Nov 2012 13:13:45 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + }, + { + "set-cookie": "mc=50951889-343da-16f7e-ae952; expires=Mon, 05-May-2014 13:13:45 GMT; path=/; domain=.quantserve.com" + }, + { + "p3p": "CP=\"NOI DSP COR NID CURa ADMa DEVa PSAo PSDo OUR SAMa IND COM NAV\"" + }, + { + "cache-control": "private, no-cache, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 04 Aug 1978 12:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:13:45 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Sat, 17 Nov 2012 13:13:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:45 GMT" + }, + { + "content-length": "1140" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-transform, max-age=1209600" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:45 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lang=\"v=2&lang=en-us\"; Version=1; Domain=linkedin.com; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "jguBxDxCP8A3strRU6z0Sw==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:13:49 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "8e0b81c43c423fc037b2dad153acf44b" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "lighttpd" + }, + { + "set-cookie": "lang=\"v=2&lang=en-us\"; Version=1; Domain=linkedin.com; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "jguBxDxCP8A3strRU6z0Sw==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "image/x-icon" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:13:49 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "8e0b81c43c423fc037b2dad153acf44b" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Wed, 22 Jun 2011 20:28:00 GMT" + }, + { + "content-length": "1150" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Thu, 16 Aug 2012 01:24:42 GMT" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1044" + }, + { + "cache-control": "max-age=24721219" + }, + { + "expires": "Fri, 16 Aug 2013 16:14:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Wed, 17 Oct 2012 23:09:52 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9168" + }, + { + "cache-control": "max-age=30168335" + }, + { + "expires": "Fri, 18 Oct 2013 17:19:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:13:51 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 04 Aug 1978 12:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:13:51 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "35" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "168222" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "server": "GFE/2.0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:51 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Fri, 02 Nov 2012 18:10:36 GMT" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-li-uuid": "eAzMxNUMwxJwGtyV9ioAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=31525993" + }, + { + "expires": "Sun, 03 Nov 2013 10:27:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:51 GMT" + }, + { + "content-length": "223" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Sat, 01 Sep 2012 00:58:09 GMT" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-li-uuid": "CCdnnfDTwhJwlNCV9ioAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=26048872" + }, + { + "expires": "Sun, 01 Sep 2013 01:01:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:51 GMT" + }, + { + "content-length": "11160" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lang=\"v=2&lang=en-us\"; Version=1; Domain=linkedin.com; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "AZRbIR9V68fBQlYZzQoS1w==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:13:54 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "01945b211f55ebc7c1425619cd0a12d7" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Wed, 22 Jun 2011 20:28:00 GMT" + }, + { + "content-length": "4714" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 04 Aug 1978 12:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:13:54 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:13:54 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "35" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "168226" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "server": "GFE/2.0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:54 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "lang=\"v=2&lang=en-us\"; Version=1; Domain=linkedin.com; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "wL1PItpHScLBRl0PVkiLLQ==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:13:59 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "c0bd4f22da4749c2c1465d0f56488b2d" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Wed, 22 Jun 2011 20:28:00 GMT" + }, + { + "content-length": "4714" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:13:59 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 04 Aug 1978 12:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:13:59 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "35" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "168230" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "server": "GFE/2.0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:13:59 GMT" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "vZHDyRjuiQCkhZBzyxGqrg==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:01 GMT" + }, + { + "age": "3" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT" + }, + { + "content-length": "6176" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Tue, 02 Oct 2012 07:53:23 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4012" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=28752189" + }, + { + "expires": "Wed, 02 Oct 2013 07:57:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:02 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Mon, 29 Oct 2012 17:17:34 GMT" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "628" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=3381907" + }, + { + "expires": "Wed, 12 Dec 2012 16:39:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:02 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "1044" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31490642" + }, + { + "expires": "Sun, 03 Nov 2013 00:38:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:02 GMT" + }, + { + "connection": "keep-alive" + }, + { + "last-modified": "Fri, 02 Nov 2012 18:36:32 GMT" + }, + { + "x-li-uuid": "KMg5e7HswhIQwgDTIysAAA==" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Wed, 31 Oct 2012 00:20:08 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "17928" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31230754" + }, + { + "expires": "Thu, 31 Oct 2013 00:26:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:02 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Tue, 23 Oct 2012 10:10:40 GMT" + }, + { + "content-type": "text/css" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-li-uuid": "YP+9O9z6wRIwf5dQLCsAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11863" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=30574946" + }, + { + "expires": "Wed, 23 Oct 2013 10:16:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:02 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Mon, 22 Oct 2012 17:10:42 GMT" + }, + { + "content-type": "text/javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "77011" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=30513689" + }, + { + "expires": "Tue, 22 Oct 2013 17:15:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:02 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "352" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:14:05 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "vZHDyRjuiQCkhZBzyxGqrg==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "0" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "image/gif" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:04 GMT" + }, + { + "age": "1" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT" + }, + { + "content-length": "6176" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "last-modified": "Fri, 02 Nov 2012 09:02:37 GMT" + }, + { + "expires": "Fri, 09 Nov 2012 09:02:37 GMT" + }, + { + "content-type": "application/ocsp-response" + }, + { + "content-transfer-encoding": "binary" + }, + { + "content-length": "1186" + }, + { + "cache-control": "max-age=503312, public, no-transform, must-revalidate" + }, + { + "date": "Sat, 03 Nov 2012 13:14:05 GMT" + }, + { + "nncoection": "close" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:14:06 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 04 Aug 1978 12:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:14:06 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "35" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "168237" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "server": "GFE/2.0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "content-length": "35" + }, + { + "x-content-type-options": "nosniff" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "age": "168237" + }, + { + "server": "GFE/2.0" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:06 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "X-LI-IDC=C1" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 22 Aug 2012 09:55:42 GMT" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:08 GMT" + }, + { + "x-fs-uuid": "4062fd4fc89b6346ee2b61950a9840a5" + }, + { + "x-li-uuid": "QGL9T8ibY0buK2GVCphApQ==" + }, + { + "age": "1" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "rDlCGMNjprrsLUOMpHhJIw==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:09 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT" + }, + { + "content-length": "0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "352" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:14:09 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "X-LI-IDC=C1" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 22 Aug 2012 09:55:42 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:09 GMT" + }, + { + "x-fs-uuid": "4062fd4fc89b6346ee2b61950a9840a5" + }, + { + "x-li-uuid": "CDPTy/MVwxKQFKu9mysAAA==" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Tue, 02 Oct 2012 17:09:44 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-li-uuid": "YP+9O9z6wRIwf5dQLCsAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "64" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=28813847" + }, + { + "expires": "Thu, 03 Oct 2013 01:04:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Wed, 31 Oct 2012 19:11:14 GMT" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-li-uuid": "iA7sd9nTwhIQefs/LCsAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=31463319" + }, + { + "expires": "Sat, 02 Nov 2013 17:02:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:09 GMT" + }, + { + "content-length": "603" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1156" + }, + { + "last-modified": "Fri, 18 Apr 2008 18:03:54 GMT" + }, + { + "etag": "1208541834000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=5196477" + }, + { + "expires": "Wed, 02 Jan 2013 16:42:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "3476" + }, + { + "last-modified": "Thu, 01 Sep 2011 13:46:08 GMT" + }, + { + "etag": "1314884768000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=29243668" + }, + { + "expires": "Tue, 08 Oct 2013 00:28:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1465" + }, + { + "last-modified": "Wed, 15 Dec 2010 19:56:09 GMT" + }, + { + "etag": "1292442969000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=5723024" + }, + { + "expires": "Tue, 08 Jan 2013 18:57:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1705" + }, + { + "last-modified": "Wed, 13 May 2009 06:47:06 GMT" + }, + { + "etag": "1242197226000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=28717727" + }, + { + "expires": "Tue, 01 Oct 2013 22:22:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1748" + }, + { + "last-modified": "Mon, 13 Feb 2012 04:16:54 GMT" + }, + { + "etag": "1329106614000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=29613032" + }, + { + "expires": "Sat, 12 Oct 2013 07:04:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2115" + }, + { + "last-modified": "Mon, 06 Jun 2011 11:28:28 GMT" + }, + { + "etag": "1307359708000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=29255048" + }, + { + "expires": "Tue, 08 Oct 2013 03:38:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2065" + }, + { + "last-modified": "Fri, 15 Aug 2008 06:35:34 GMT" + }, + { + "etag": "1218782134000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "cache-control": "max-age=23989474" + }, + { + "expires": "Thu, 08 Aug 2013 04:58:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-cdn": "AKAM" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1777" + }, + { + "last-modified": "Sun, 06 Apr 2008 16:44:40 GMT" + }, + { + "etag": "1207500280000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=24015458" + }, + { + "expires": "Thu, 08 Aug 2013 12:11:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2536" + }, + { + "last-modified": "Sun, 17 Apr 2011 11:26:00 GMT" + }, + { + "etag": "1303039560000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=30996570" + }, + { + "expires": "Mon, 28 Oct 2013 07:23:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "1445" + }, + { + "last-modified": "Sun, 14 Dec 2008 19:47:28 GMT" + }, + { + "etag": "1229284048000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31023826" + }, + { + "expires": "Mon, 28 Oct 2013 14:57:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "11785" + }, + { + "last-modified": "Tue, 21 Feb 2012 04:44:27 GMT" + }, + { + "etag": "1329799467000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=29267475" + }, + { + "expires": "Tue, 08 Oct 2013 07:05:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:14:11 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 04 Aug 1978 12:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:14:11 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "35" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "168242" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "server": "GFE/2.0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "content-length": "35" + }, + { + "x-content-type-options": "nosniff" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "age": "168242" + }, + { + "server": "GFE/2.0" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:11 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "1013" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:44:36 GMT" + }, + { + "etag": "1351921476485" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31508935" + }, + { + "expires": "Sun, 03 Nov 2013 05:43:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:11 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-li-uuid": "uBgHimv9whIwouPuKysAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "X-LI-IDC=C1" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 09 Aug 2012 02:40:28 GMT" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:12 GMT" + }, + { + "x-fs-uuid": "b73d9dcff4c8d40067468ef689e05a93" + }, + { + "x-li-uuid": "tz2dz/TI1ABnRo72ieBakw==" + }, + { + "age": "1" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "6507" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "+8Oyp3i1cl6p243WV3LM6g==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:13 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT" + }, + { + "content-length": "0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "537" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:14:13 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "text/html" + }, + { + "content-length": "2469" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:14:13 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "text/javascript" + }, + { + "last-modified": "Tue, 08 May 2012 20:09:07 GMT" + }, + { + "date": "Fri, 02 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:30:09 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "server": "sffe" + }, + { + "content-length": "321" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "81845" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Tue, 21 Feb 2012 01:03:49 GMT" + }, + { + "date": "Fri, 02 Nov 2012 20:03:29 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 20:03:29 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "server": "sffe" + }, + { + "content-length": "24156" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "61845" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Fri, 02 Nov 2012 18:10:35 GMT" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=31525781" + }, + { + "expires": "Sun, 03 Nov 2013 10:23:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:13 GMT" + }, + { + "content-length": "94" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"5f7cc9080cad02333445367dae64546d:1351006466\"" + }, + { + "last-modified": "Tue, 23 Oct 2012 15:34:26 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=3600" + }, + { + "date": "Sat, 03 Nov 2012 13:14:14 GMT" + }, + { + "content-length": "1028" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 18 Jun 2012 13:12:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"eb63c14544dcd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "2955" + }, + { + "date": "Sat, 03 Nov 2012 13:14:14 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:14:14 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 16:25:49 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 16:25:49 GMT" + }, + { + "etag": "46977404F0473696BBDC518B1845C60E809A3249" + }, + { + "cache-control": "max-age=356494,public,no-transform,must-revalidate" + }, + { + "x-ocsp-reponder-id": "t8edcaocsp6" + }, + { + "content-length": "471" + }, + { + "connection": "close" + }, + { + "content-type": "application/ocsp-response" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"65786c291a4603aa5150a1884452838d:1271351254\"" + }, + { + "last-modified": "Thu, 15 Apr 2010 17:07:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=2144448000" + }, + { + "date": "Sat, 03 Nov 2012 13:14:14 GMT" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"4cdd47b7bd15f75838435f1207ac1414:1351006993\"" + }, + { + "last-modified": "Tue, 23 Oct 2012 15:43:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=315360000" + }, + { + "date": "Sat, 03 Nov 2012 13:14:14 GMT" + }, + { + "content-length": "12232" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "CP=\"COM NAV INT STA NID OUR IND NOI\"" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "set-cookie": "cckz=1mcwy3r; Domain=media6degrees.com; Expires=Thu, 02-May-2013 13:14:15 GMT; Path=/" + }, + { + "location": "http://action.media6degrees.com/orbserv/nsjs?ncv=33&ns=299&pcv=39&nc=1&pixId=13086&cckz=true" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:14:14 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:14:15 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "X-LI-IDC=C1" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 17 Jul 2012 23:10:45 GMT" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:15 GMT" + }, + { + "x-fs-uuid": "1034b0b6c77d1f91819a2d929764b582" + }, + { + "x-li-uuid": "EDSwtsd9H5GBmi2Sl2S1gg==" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "6507" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "iPSByYTV24172TMFAcPcSg==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:15 GMT" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT" + }, + { + "content-length": "0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "539" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "CP=\"COM NAV INT STA NID OUR IND NOI\"" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "set-cookie": "cckz=1mcwy3s; Domain=media6degrees.com; Expires=Thu, 02-May-2013 13:14:16 GMT; Path=/" + }, + { + "location": "http://action.media6degrees.com/orbserv/nsjs?ncv=33&ns=299&pcv=39&nc=1&pixId=13086&cckz=true" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "CP=\"COM NAV INT STA NID OUR IND NOI\"" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "set-cookie": "JSESSIONID=CE33DFE7D94779C13B04C4D9B43D7792; Path=/orbserv; HttpOnly" + }, + { + "content-type": "text/html;charset=ISO-8859-1" + }, + { + "content-language": "en-US" + }, + { + "content-length": "5" + }, + { + "date": "Sat, 03 Nov 2012 13:14:15 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "text/html" + }, + { + "content-length": "841" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "u=8|0BAgYJ9UoGCfVKAAAAAAAAQEAAQIhdawAARg9fRc3AAAAAAT9PvgAAAAAAu9ZfgAAAAAO_VtUCBMBAAuBLQA; Version=1; Domain=.agkn.com; Max-Age=63072000; Expires=Mon, 03-Nov-2014 13:14:16 GMT; Path=/" + }, + { + "p3p": "CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "image/gif;charset=ISO-8859-1" + }, + { + "content-language": "en-US" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:14:15 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "X-LI-IDC=C1" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 17 Jul 2012 23:10:45 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "x-fs-uuid": "1034b0b6c77d1f91819a2d929764b582" + }, + { + "x-li-uuid": "EDSwtsd9H5GBmi2Sl2S1gg==" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "6507" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "2036" + }, + { + "last-modified": "Thu, 29 Nov 2007 19:09:10 GMT" + }, + { + "etag": "1196363350000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31005797" + }, + { + "expires": "Mon, 28 Oct 2013 09:57:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-li-uuid": "uBgHimv9whIwouPuKysAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "access-control-allow-origin": "http://www.linkedin.com" + }, + { + "last-modified": "Sat, 15 Sep 2012 06:22:35 GMT" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=27345738" + }, + { + "expires": "Mon, 16 Sep 2013 01:16:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "content-length": "146" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-type": "image/jpeg" + }, + { + "last-modified": "Tue, 03 Jul 2012 21:15:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 03:30:07 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 03:30:07 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "server": "sffe" + }, + { + "content-length": "19787" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "35049" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 18 Jun 2012 13:12:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"eb63c14544dcd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "2955" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"84332e7556647543d5f87647f37a8a6d:1346087966\"" + }, + { + "last-modified": "Mon, 27 Aug 2012 17:19:26 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=600" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "content-length": "741" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 04 Aug 1978 12:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "35" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "168247" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "server": "GFE/2.0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "content-length": "35" + }, + { + "x-content-type-options": "nosniff" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "age": "168247" + }, + { + "server": "GFE/2.0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"f13746374fa151b24abd8bf99a396878:1347294343\"" + }, + { + "last-modified": "Mon, 10 Sep 2012 16:25:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/png" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=2144448000" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "content-length": "1028" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"4d5ead3cfaa1fd96263197170ccaed07:1347294382\"" + }, + { + "last-modified": "Mon, 10 Sep 2012 16:26:22 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1507" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "max-age=2144448000" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:16 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "X-LI-IDC=C1" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 05 Aug 2012 15:35:43 GMT" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:18 GMT" + }, + { + "x-fs-uuid": "e4dcbadff47540485aebb5d079a66252" + }, + { + "x-li-uuid": "5Ny63/R1QEha67XQeaZiUg==" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "6507" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-li-uuid": "qwi+h66wCYWzSNcKexV4yw==" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:18 GMT" + }, + { + "age": "1" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1672258277\"" + }, + { + "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT" + }, + { + "content-length": "0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "538" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "CP=\"COM NAV INT STA NID OUR IND NOI\"" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "set-cookie": "JSESSIONID=AA69DF8838B33636B86F3AD5917D28DD; Path=/orbserv; HttpOnly" + }, + { + "content-type": "text/html;charset=ISO-8859-1" + }, + { + "content-language": "en-US" + }, + { + "content-length": "5" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "text/html" + }, + { + "content-length": "859" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "X-LI-IDC=C1" + }, + { + "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\"" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 05 Aug 2012 15:35:43 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-language": "en-US" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + }, + { + "x-fs-uuid": "e4dcbadff47540485aebb5d079a66252" + }, + { + "x-li-uuid": "aGvE/vUVwxKwMlIRJCsAAA==" + }, + { + "age": "0" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "0" + }, + { + "pragma": "no-cache" + }, + { + "content-length": "6507" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "u=8|0BAgYJ9UoGCfVKwAAAAABAQEAAQQhdawAARg9fRc3AAAAAAT9PvgAAAAAAu5WuAAAAAAO_VtUCBMBAAuBLQA; Version=1; Domain=.agkn.com; Max-Age=63072000; Expires=Mon, 03-Nov-2014 13:14:19 GMT; Path=/" + }, + { + "p3p": "CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "expires": "Sat, 01 Jan 2000 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "image/gif;charset=ISO-8859-1" + }, + { + "content-language": "en-US" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:14:18 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/png" + }, + { + "content-length": "3183" + }, + { + "last-modified": "Tue, 04 Mar 2008 16:53:17 GMT" + }, + { + "etag": "1204649597000" + }, + { + "server": "Jetty(6.1.26)" + }, + { + "x-cdn": "AKAM" + }, + { + "cache-control": "max-age=31199347" + }, + { + "expires": "Wed, 30 Oct 2013 15:43:26 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-li-uuid": "uBgHimv9whIwouPuKysAAA==" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Mon, 18 Jun 2012 13:12:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"eb63c14544dcd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "2955" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 04 Aug 1978 12:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + }, + { + "server": "QS" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "35" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "age": "168250" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "server": "GFE/2.0" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Thu, 01 Nov 2012 14:30:09 GMT" + }, + { + "content-length": "35" + }, + { + "x-content-type-options": "nosniff" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Wed, 19 Apr 2000 11:43:00 GMT" + }, + { + "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate" + }, + { + "age": "168250" + }, + { + "server": "GFE/2.0" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:14:19 GMT" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "pragma": "no-cache" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_29.json b/jetty-http2/http2-hpack/src/test/resources/data/story_29.json new file mode 100644 index 00000000000..01bdbbf8cb1 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_29.json @@ -0,0 +1,13780 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "301" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "location": "http://www.msn.com/" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "date": "Sat, 03 Nov 2012 13:29:27 GMT" + }, + { + "content-length": "142" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "p3p": "CP=\"NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND\"" + }, + { + "set-cookie": "SRCHUSR=AUTOREDIR=0&GEOVAR=&DOB=20121103; expires=Mon, 03-Nov-2014 13:29:29 GMT; domain=.msn.com; path=/" + }, + { + "errorcodecount": "[0:0]" + }, + { + "s": "CO3SCH010020101" + }, + { + "edge-control": "no-store" + }, + { + "date": "Sat, 03 Nov 2012 13:29:28 GMT" + }, + { + "content-length": "41648" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=43200" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"808cfaf3c1ac81:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "43" + }, + { + "age": "7374" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Mon, 29 Oct 2007 15:02:13 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 23:26:35 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=86400,public" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"078def13c1fcd1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "43" + }, + { + "age": "33322" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Fri, 20 Apr 2012 21:31:28 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 04:14:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"083df89b6bac81:0\"" + }, + { + "server": "BLUMPPSTCA08" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "1162" + }, + { + "age": "9388284" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Tue, 20 May 2008 20:17:34 GMT" + }, + { + "expires": "Wed, 17 Jul 2013 21:38:05 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=86400,public" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"078def13c1fcd1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "43" + }, + { + "age": "33322" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Fri, 20 Apr 2012 21:31:28 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 04:14:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"096b38d19cc1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "417" + }, + { + "age": "11654605" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Tue, 03 May 2011 20:32:28 GMT" + }, + { + "expires": "Fri, 21 Jun 2013 16:06:04 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"99789f9faea8cd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "2712" + }, + { + "age": "378940" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Fri, 12 Oct 2012 19:20:21 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 04:13:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"d6db97976eb9cd1:0\"" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "3262" + }, + { + "age": "37907" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:54:50 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 02:57:42 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"6c2a9d5170b1cd1:0\"" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "4648" + }, + { + "age": "23683" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Tue, 23 Oct 2012 22:47:02 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 06:54:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/x-icon" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0922651f38cb1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "4286" + }, + { + "age": "9388299" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Tue, 10 Aug 2010 00:03:00 GMT" + }, + { + "expires": "Wed, 17 Jul 2013 21:37:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"f9f8904b5ab9cd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "4352" + }, + { + "age": "46151" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:29:32 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 00:40:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"8437263c89b8cd1:0\"" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "6131" + }, + { + "age": "23313" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 23:33:02 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 07:00:56 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"54a642c148b9cd1:0\"" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "5522" + }, + { + "age": "23304" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 22:23:59 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 07:01:05 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"f5d7f6f68b8cd1:0\"" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "4048" + }, + { + "age": "23326" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 19:38:15 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 07:00:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"789825b3b68cc1:0\"" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "7075" + }, + { + "age": "304691" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Wed, 31 Aug 2011 18:27:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 00:51:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"6a4618d83cb9cd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "11544" + }, + { + "age": "59087" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 20:58:43 GMT" + }, + { + "expires": "Fri, 09 Nov 2012 21:04:42 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"188d971c36b9cd1:0\"" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "3753" + }, + { + "age": "23326" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 20:10:32 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 07:00:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80a9243afa8cd1:0\"" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "2135" + }, + { + "age": "64967" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Fri, 12 Oct 2012 19:24:57 GMT" + }, + { + "expires": "Fri, 09 Nov 2012 19:26:42 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"da259a60afb9cd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "6786" + }, + { + "age": "9961" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 10:38:35 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 10:43:28 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"3a2bfd7658b9cd1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "6859" + }, + { + "age": "47464" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:16:26 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 00:18:25 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"feefae84ab9cd1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "7066" + }, + { + "age": "23304" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 22:39:23 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 07:01:05 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"4b1b97dcc0b9cd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "14928" + }, + { + "age": "2676" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 12:43:44 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 12:44:53 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80f314cf17b7cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "23864" + }, + { + "age": "290866" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 03:28:35 GMT" + }, + { + "expires": "Thu, 31 Oct 2013 04:41:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/jpeg" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"9c71d229a3b9cd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "7497" + }, + { + "age": "14681" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 09:11:09 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 09:24:48 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=300" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=43200" + }, + { + "content-type": "application/x-javascript" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"91588811bb8bcd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "2420" + }, + { + "age": "41017" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Wed, 05 Sep 2012 23:06:23 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:05:53 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0e49dbec5aecb1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "4082" + }, + { + "age": "8615761" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 07 Jan 2011 23:51:04 GMT" + }, + { + "expires": "Fri, 26 Jul 2013 20:13:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"ac1668bfc52ca1:0\"" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "657" + }, + { + "age": "159348" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Thu, 22 Oct 2009 09:46:35 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 17:13:42 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "application/x-javascript" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"803ab9aa463acd1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "24630" + }, + { + "age": "9388297" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:19:05 GMT" + }, + { + "expires": "Wed, 17 Jul 2013 21:37:53 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "application/x-javascript" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"02bfb6a29b7cd1:0\"" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "65670" + }, + { + "age": "285810" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 05:34:38 GMT" + }, + { + "expires": "Thu, 31 Oct 2013 06:06:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80d88a9463acd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "74" + }, + { + "age": "8077925" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:19:03 GMT" + }, + { + "expires": "Fri, 02 Aug 2013 01:37:25 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"8097d798463acd1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "48" + }, + { + "age": "9389765" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:18:35 GMT" + }, + { + "expires": "Wed, 17 Jul 2013 21:13:25 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"5bc3dfd117b7cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "6234" + }, + { + "age": "290867" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 03:28:39 GMT" + }, + { + "expires": "Thu, 31 Oct 2013 04:41:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"801e6b9c463acd1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "1117" + }, + { + "age": "8614139" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:18:41 GMT" + }, + { + "expires": "Fri, 26 Jul 2013 20:40:31 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"077efa8463acd1:0\"" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "43" + }, + { + "age": "11574965" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:19:02 GMT" + }, + { + "expires": "Sat, 22 Jun 2013 14:13:25 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"8097d798463acd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "1142" + }, + { + "age": "9388300" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:18:35 GMT" + }, + { + "expires": "Wed, 17 Jul 2013 21:37:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"8086f4a5463acd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "172" + }, + { + "age": "9388300" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:18:57 GMT" + }, + { + "expires": "Wed, 17 Jul 2013 21:37:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "application/x-javascript" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"8016f7a74e67cc1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "421" + }, + { + "age": "9389765" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Tue, 30 Aug 2011 19:54:41 GMT" + }, + { + "expires": "Wed, 17 Jul 2013 21:13:25 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"9a7af237eb5cd1:0\"" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "5436" + }, + { + "age": "462287" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Mon, 29 Oct 2012 02:35:10 GMT" + }, + { + "expires": "Tue, 29 Oct 2013 05:04:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "content-length": "1640" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "3989" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10263730-T100595690-C40000000000114208" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "p3p": "CP=\"NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND\"" + }, + { + "set-cookie": "SRCHD=MS=2546729&D=2546729&AF=NOFORM; expires=Mon, 03-Nov-2014 13:29:30 GMT; domain=.msn.com; path=/" + }, + { + "errorcodecount": "[0:0]" + }, + { + "s": "CO3SCH010133009" + }, + { + "edge-control": "no-store" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "content-length": "2197" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://c.atdmt.com/c.gif?udc=true&di=340&pi=7317&ps=95101&lng=en-us&tp=http%3A%2F%2Fwww.msn.com%2Fdefaultwpe3w.aspx&rid=e32241cc231e4226b91543c154dd3b7e&rnd=1351949370023&rf=&scr=1366x768&RedC=c.msn.com&MXFR=3D632B5B5356602B36252F56575660EB" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "MUID=3D632B5B5356602B36252F56575660EB&TUID=1; domain=.msn.com; expires=Mon, 03-Nov-2014 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "content-length": "0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-length": "42" + }, + { + "content-type": "image/gif" + }, + { + "content-location": "http://spe.atdmt.com/images/pixel.gif" + }, + { + "expires": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:29 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/3642305/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "server": "GFE/2.0" + }, + { + "content-type": "text/html; charset=UTF-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001001" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=1800" + }, + { + "content-type": "text/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0287ded7fb9cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "1811" + }, + { + "age": "1765" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:58:56 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:30:04 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=1800" + }, + { + "content-type": "text/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80722a7c098cc1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "9346" + }, + { + "age": "1170" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Tue, 01 Nov 2011 18:04:09 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:00 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=1800" + }, + { + "content-type": "text/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0af38a5c098cc1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "20808" + }, + { + "age": "1411" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Tue, 01 Nov 2011 18:04:06 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:35:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=1800" + }, + { + "content-type": "text/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"8091e4ec7fb9cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "1142" + }, + { + "age": "1226" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:58:55 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:39:04 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://c.msn.com/c.gif?udc=true&di=340&pi=7317&ps=95101&lng=en-us&tp=http%3A%2F%2Fwww.msn.com%2Fdefaultwpe3w.aspx&rid=e32241cc231e4226b91543c154dd3b7e&rnd=1351949370023&rf=&scr=1366x768&MUID=39C1843BD7CB679E06238036D4CB670B&cb=1cdb9c7414258b0" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "SRM_M=39C1843BD7CB679E06238036D4CB670B; domain=c.atdmt.com; expires=Mon, 03-Nov-2014 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "content-length": "0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=1800" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"299a82bdeb9cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-length": "20046" + }, + { + "age": "1074" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 15:28:42 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:36 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Fri, 17 Aug 2012 14:27:55 GMT" + }, + { + "date": "Fri, 02 Nov 2012 19:34:58 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 19:34:58 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "46" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "64473" + }, + { + "cache-control": "public, max-age=86400" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 07:00:23 GMT" + }, + { + "server": "Jetty(6.1.22)" + }, + { + "p3p": "policyref=\"/w3c/policy.xml\", CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "x-powered-by": "Mirror Image Internet" + }, + { + "via": "1.1 bfi061004 (MII-APC/2.2)" + }, + { + "x-mii-cache-hit": "1" + }, + { + "content-length": "42" + }, + { + "keep-alive": "timeout=2" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0e2349e463acd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "93" + }, + { + "age": "8077926" + }, + { + "date": "Sat, 03 Nov 2012 13:29:31 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:18:44 GMT" + }, + { + "expires": "Fri, 02 Aug 2013 01:37:25 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "set-cookie": "pudm_AAAA=MLuxc4uHAF5HEldAttN+mTMH5l3UFcGfjYAvMSjMMwDWP3TDUWl1; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:29:31 GMT; Path=/" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "x-proc-data": "pd3-bgas02-0" + }, + { + "content-type": "application/javascript;charset=ISO-8859-1" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "p3p": "CP=\"NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND\"" + }, + { + "set-cookie": "SRCHD=SM=1&MS=2546729&D=2546729&AF=NOFORM; expires=Mon, 03-Nov-2014 13:29:31 GMT; domain=.msn.com; path=/" + }, + { + "errorcodecount": "[0:0]" + }, + { + "s": "CO3SCH010120128" + }, + { + "edge-control": "no-store" + }, + { + "date": "Sat, 03 Nov 2012 13:29:30 GMT" + }, + { + "content-length": "1672" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "application/x-javascript" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0a420aa463acd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "387" + }, + { + "age": "11654712" + }, + { + "date": "Sat, 03 Nov 2012 13:29:31 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:19:04 GMT" + }, + { + "expires": "Fri, 21 Jun 2013 16:04:19 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/jpeg" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"05ba19a463acd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "4842" + }, + { + "age": "11654572" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:18:38 GMT" + }, + { + "expires": "Fri, 21 Jun 2013 16:06:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80b325a7463acd1:0\"" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "1105" + }, + { + "age": "8614141" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "last-modified": "Fri, 25 May 2012 07:18:59 GMT" + }, + { + "expires": "Fri, 26 Jul 2013 20:40:31 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "content-length": "562" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "884" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10669318-T100595843-C108000000000115722" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "3114" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-radid": "P10603404-T100595756-C48000000000113484" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:31 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1323" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:31 GMT" + }, + { + "content-length": "1336" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "3147" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10720545-T100595939-C52000000000120598" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "406" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-radid": "P3782944-T100582739-C521263" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:31 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "325" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/gif" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0bd514f14ac31:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "content-length": "85" + }, + { + "age": "12894277" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "last-modified": "Tue, 15 Jul 2003 16:49:38 GMT" + }, + { + "expires": "Fri, 07 Jun 2013 07:44:55 GMT" + }, + { + "connection": "keep-alive" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31535999" + }, + { + "content-type": "image/gif" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "2710" + }, + { + "age": "3659370" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "expires": "Sun, 22 Sep 2013 05:00:01 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31508189" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "9220" + }, + { + "age": "3659358" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "expires": "Sat, 21 Sep 2013 21:16:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31338077" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "3607" + }, + { + "age": "3400121" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "expires": "Sun, 22 Sep 2013 22:02:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "last-modified": "Fri, 02 Nov 2012 09:35:33 GMT" + }, + { + "etag": "\"1411999884f419ea8219bf9b531a9c66\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "application/javascript; charset=utf-8" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3260" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "CP=\"CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND UNI COM NAV INT\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/json; charset=utf-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "etag": "\"377d257f2d2e294916143c069141c1c5:1328738114\"" + }, + { + "last-modified": "Wed, 08 Feb 2012 21:55:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "43" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "CP=\"CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND UNI COM NAV INT\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:10:52 GMT" + }, + { + "pragma": "no-cache" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "x-content-type-options": "nosniff" + }, + { + "status": "200 OK" + }, + { + "content-type": "application/javascript;charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "889" + }, + { + "server": "tfe" + }, + { + "vary": "Accept-Encoding" + }, + { + "cache-control": "no-cache, no-store, must-revalidate, post-check=0, pre-check=0" + }, + { + "expires": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "x-transaction": "49df427f743e57d8" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "expires": "Tue, 31 Mar 1981 05:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache, no-store, must-revalidate, pre-check=0, post-check=0" + }, + { + "set-cookie": "guest_id=v1%3A135194937257731566; Expires=Mon, 3-Nov-2014 13:29:32 GMT; Path=/; Domain=.twitter.com" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "65" + }, + { + "server": "tfe" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "last-modified": "Fri, 02 Nov 2012 09:48:13 GMT" + }, + { + "etag": "\"b036a791811effc968bfcb43fa6d6910\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7242" + }, + { + "date": "Sat, 03 Nov 2012 13:29:32 GMT" + }, + { + "connection": "keep-alive" + }, + { + "p3p": "CP=\"CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND UNI COM NAV INT\"" + }, + { + "cache-control": "public, max-age=1800" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:34 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 16:28:26 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 16:28:26 GMT" + }, + { + "etag": "412224A3234E88A2760468333271010BB1C6D1AA" + }, + { + "cache-control": "max-age=355731,public,no-transform,must-revalidate" + }, + { + "x-ocsp-reponder-id": "t8edcaocsp4" + }, + { + "content-length": "471" + }, + { + "connection": "close" + }, + { + "content-type": "application/ocsp-response" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/ocsp-response" + }, + { + "content-transfer-encoding": "Binary" + }, + { + "content-length": "1938" + }, + { + "connection": "Close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:34 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 16:28:26 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 16:28:26 GMT" + }, + { + "etag": "412224A3234E88A2760468333271010BB1C6D1AA" + }, + { + "cache-control": "max-age=355731,public,no-transform,must-revalidate" + }, + { + "x-ocsp-reponder-id": "t8edcaocsp4" + }, + { + "content-length": "471" + }, + { + "connection": "close" + }, + { + "content-type": "application/ocsp-response" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-aspnetmvc-version": "4.0" + }, + { + "x-ua-compatible": "IE=Edge;chrome=1" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "content-length": "28018" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 06:48:54 GMT" + }, + { + "server": "Jetty(6.1.22)" + }, + { + "p3p": "policyref=\"/w3c/policy.xml\", CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "x-powered-by": "Mirror Image Internet" + }, + { + "via": "1.1 bfi061001 (MII-APC/2.2)" + }, + { + "x-mii-cache-hit": "1" + }, + { + "content-length": "42" + }, + { + "keep-alive": "timeout=2" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"80ebcf5152b0cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "6717" + }, + { + "age": "1026619" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 12:39:47 GMT" + }, + { + "expires": "Tue, 22 Oct 2013 16:19:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "application/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0195ab552b0cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "8659" + }, + { + "age": "1026617" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 12:42:34 GMT" + }, + { + "expires": "Tue, 22 Oct 2013 16:19:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"707a74ac52b0cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "9389" + }, + { + "age": "1026617" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 12:42:19 GMT" + }, + { + "expires": "Tue, 22 Oct 2013 16:19:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"f0edab8b52b0cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "3749" + }, + { + "age": "1026645" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 12:41:24 GMT" + }, + { + "expires": "Tue, 22 Oct 2013 16:18:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/x-icon" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-aspnetmvc-version": "4.0" + }, + { + "x-ua-compatible": "IE=Edge;chrome=1" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "content-length": "4286" + }, + { + "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"951751d2bdb7cd1:0\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001001" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431991" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "773" + }, + { + "age": "416777" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 17:43:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431989" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "4747" + }, + { + "age": "69970" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 18:03:14 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001004" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=423916" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "45125" + }, + { + "age": "4791" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 09:55:00 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public,max-age=31536000" + }, + { + "content-length": "42060" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"1ac2aef461a9cc1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "p3p": "CP=\"ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI\"" + }, + { + "vtag": "279606632500000000" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "age": "3987586" + }, + { + "date": "Sat, 03 Nov 2012 13:29:36 GMT" + }, + { + "last-modified": "Tue, 22 Nov 2011 21:59:06 GMT" + }, + { + "expires": "Wed, 18 Sep 2013 09:49:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:36 GMT" + }, + { + "content-length": "954" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "2008" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG7]PCxrx)0s]#%2L_'x%SEV/hnJip4FQV_eKj?9kb10I3SSI79ox)!lG@t]; path=/; expires=Fri, 01-Feb-2013 13:29:36 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:29:36 GMT" + }, + { + "content-length": "615" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:29:35 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "381" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "42" + }, + { + "allow": "GET" + }, + { + "expires": "Tue, 06 Nov 2012 04:51:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:29:36 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG7]PCxrx)0s]#%2L_'x%SEV/hnJip4FQV_eKj?9kb10I3SSI79ox)!lG@t]; path=/; expires=Fri, 01-Feb-2013 13:29:36 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-length": "43" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:29:36 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-msadid": "300089389.300024620" + }, + { + "date": "Sat, 03 Nov 2012 13:29:36 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "2290" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "40789" + }, + { + "allow": "GET" + }, + { + "expires": "Thu, 08 Nov 2012 21:57:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "20802" + }, + { + "allow": "GET" + }, + { + "expires": "Mon, 05 Nov 2012 06:30:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431968" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "4319" + }, + { + "age": "1707" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 13:00:38 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431760" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "5321" + }, + { + "age": "14923" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 09:16:54 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431996" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "4605" + }, + { + "age": "46358" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 00:36:55 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431925" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "4097" + }, + { + "age": "64344" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:35:58 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=432000" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "4692" + }, + { + "age": "32851" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 04:22:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431754" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "2555" + }, + { + "age": "14924" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 09:16:47 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431758" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "4026" + }, + { + "age": "54890" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 22:10:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431997" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "4589" + }, + { + "age": "403007" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 21:32:47 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431990" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "3476" + }, + { + "age": "82129" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 14:40:38 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431839" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "5927" + }, + { + "age": "53455" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 22:36:01 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431993" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "4900" + }, + { + "age": "83837" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 14:12:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431997" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "4420" + }, + { + "age": "88061" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 13:01:53 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/octet-stream" + }, + { + "content-length": "2209" + }, + { + "allow": "GET" + }, + { + "expires": "Thu, 08 Nov 2012 19:27:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431982" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "5496" + }, + { + "age": "63170" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:56:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431991" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "3450" + }, + { + "age": "89554" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 12:36:54 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431990" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "2271" + }, + { + "age": "92961" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 11:40:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431991" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "4009" + }, + { + "age": "86314" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 13:30:54 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431989" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "3779" + }, + { + "age": "86708" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 13:24:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431976" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "3115" + }, + { + "age": "69186" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 18:16:07 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431990" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "4867" + }, + { + "age": "80624" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 15:05:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431993" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "5187" + }, + { + "age": "140253" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 22:31:57 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431966" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "5244" + }, + { + "age": "140817" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 22:22:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431931" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "3807" + }, + { + "age": "303973" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Mon, 05 Nov 2012 01:02:15 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431977" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "4135" + }, + { + "age": "143835" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 21:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431943" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "5096" + }, + { + "age": "64149" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:39:31 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431988" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "3801" + }, + { + "age": "125275" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 02:41:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431990" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "4499" + }, + { + "age": "144182" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 21:26:25 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/json; charset=utf-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:29:37 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-aspnetmvc-version": "4.0" + }, + { + "x-ua-compatible": "IE=Edge;chrome=1" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "content-length": "23449" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0feb9575b2cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "5942" + }, + { + "age": "717045" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 16:33:48 GMT" + }, + { + "expires": "Sat, 26 Oct 2013 06:18:57 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "application/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"0f9f3446b2cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "8528" + }, + { + "age": "717044" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 16:40:26 GMT" + }, + { + "expires": "Sat, 26 Oct 2013 06:18:58 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"968a7a9552b0cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "8149" + }, + { + "age": "1026651" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "last-modified": "Mon, 22 Oct 2012 12:41:40 GMT" + }, + { + "expires": "Tue, 22 Oct 2013 16:18:51 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/x-icon" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-aspnetmvc-version": "4.0" + }, + { + "x-ua-compatible": "IE=Edge;chrome=1" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "content-length": "4286" + }, + { + "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"951751d2bdb7cd1:0\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001004" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "content-length": "954" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "2008" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001001" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=24" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "machine": "SN1********532" + }, + { + "rendertime": "11/2/2012 8:14:13 AM" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "34971" + }, + { + "age": "39" + }, + { + "date": "Sat, 03 Nov 2012 13:29:42 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 15:14:13 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:44:02 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG3x=Cxrx)0s]#%2L_'x%SEV/hnKu94FQV_eKj?9kb10I3SSI7:0wHz@)G?)i4ZhK; path=/; expires=Fri, 01-Feb-2013 13:29:43 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "content-length": "514" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=7775467" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "machine": "SN1********532" + }, + { + "rendertime": "11/2/2012 8:14:13 AM" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "27220" + }, + { + "age": "226499" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 22:25:52 GMT" + }, + { + "expires": "Tue, 29 Jan 2013 22:25:51 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-aspnet-version": "4.0.30319" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-length": "1465" + }, + { + "content-type": "image/png" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "age": "77450" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Thu, 06 Sep 2012 03:42:16 GMT" + }, + { + "expires": "Fri, 16 Nov 2012 15:58:54 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-msadid": "300089440.299934848" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "514" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "3936" + }, + { + "age": "1664" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 11:56:42 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:35:01 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "4646" + }, + { + "age": "1653" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:42:24 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 17:14:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "14780" + }, + { + "allow": "GET" + }, + { + "expires": "Fri, 09 Nov 2012 04:45:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "41165" + }, + { + "age": "1664" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:52:34 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:31:59 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/json; charset=utf-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "location": "http://m.adnxs.com/msftcookiehandler?t=1&c=MUID%3d39C1843BD7CB679E06238036D4CB670B" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "content-length": "13" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "sess=1; path=/; expires=Sun, 04-Nov-2012 13:29:43 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "content-length": "43" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "7206" + }, + { + "age": "1871" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Tue, 30 Oct 2012 19:21:20 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:46:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "2833" + }, + { + "age": "4319" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 01:22:37 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:57:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "4141" + }, + { + "age": "1871" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 09:14:16 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:47:24 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=600" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Sat, 03 Nov 2012 13:39:43 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "machine": "SN1********529" + }, + { + "rendertime": "11/3/2012 6:29:43 AM" + }, + { + "x-rendertime": "0.017 secs" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "content-length": "6790" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "7264" + }, + { + "age": "4321" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:45:33 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:47:42 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=7776000" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "machine": "SN1********532" + }, + { + "rendertime": "11/2/2012 8:14:13 AM" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "3083" + }, + { + "age": "227101" + }, + { + "date": "Sat, 03 Nov 2012 13:29:44 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 22:24:43 GMT" + }, + { + "expires": "Tue, 29 Jan 2013 22:24:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-aspnet-version": "4.0.30319" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=7775989" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "machine": "SN1********532" + }, + { + "rendertime": "11/2/2012 8:14:13 AM" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "631" + }, + { + "age": "227144" + }, + { + "date": "Sat, 03 Nov 2012 13:29:44 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 22:23:50 GMT" + }, + { + "expires": "Tue, 29 Jan 2013 22:23:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + "x-aspnet-version": "4.0.30319" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "5366" + }, + { + "age": "2169" + }, + { + "date": "Sat, 03 Nov 2012 13:29:44 GMT" + }, + { + "last-modified": "Thu, 01 Nov 2012 23:46:05 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:23:35 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=7775981" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "5125" + }, + { + "age": "227144" + }, + { + "date": "Sat, 03 Nov 2012 13:29:44 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 22:23:41 GMT" + }, + { + "expires": "Tue, 29 Jan 2013 22:23:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "38544" + }, + { + "age": "1664" + }, + { + "date": "Sat, 03 Nov 2012 13:29:44 GMT" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:46:18 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:32:00 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, max-age=7775962" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "68447" + }, + { + "age": "227086" + }, + { + "date": "Sat, 03 Nov 2012 13:29:44 GMT" + }, + { + "last-modified": "Wed, 31 Oct 2012 22:24:21 GMT" + }, + { + "expires": "Tue, 29 Jan 2013 22:24:20 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "machine": "SN1********525" + }, + { + "rendertime": "11/3/2012 6:29:44 AM" + }, + { + "x-rendertime": "0.003 secs" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "date": "Sat, 03 Nov 2012 13:29:43 GMT" + }, + { + "content-length": "1238" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "machine": "SN1********509" + }, + { + "rendertime": "11/3/2012 6:29:44 AM" + }, + { + "set-cookie": "zip=c:cz; domain=msn.com; expires=Sat, 10-Nov-2012 14:29:44 GMT; path=/" + }, + { + "x-rendertime": "0.067 secs" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "date": "Sat, 03 Nov 2012 13:29:44 GMT" + }, + { + "content-length": "138" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-aspnetmvc-version": "4.0" + }, + { + "x-ua-compatible": "IE=Edge;chrome=1" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Sat, 03 Nov 2012 13:29:46 GMT" + }, + { + "content-length": "25630" + }, + { + "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"951751d2bdb7cd1:0\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001001" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=422586" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "818" + }, + { + "age": "321488" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 17:34:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "content-length": "954" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "1996" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001005" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG68%Cxrx)0s]#%2L_'x%SEV/hnJPh4FQV_eKj?9AMF4:V)4hY/82QjU'-Rw1Ra^uI$+VZ; path=/; expires=Fri, 01-Feb-2013 13:29:47 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "content-length": "1463" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "ntcoent-length": "42" + }, + { + "content-type": "image/gif" + }, + { + "expires": "6:29:42 AM" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "trackingid": "3bd68bdc-1e91-410e-bd92-a85913c08914" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "54" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/json; charset=utf-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "must-revalidate" + }, + { + "expires": "Mon, 05 Nov 2012 13:29:48 GMT" + }, + { + "set-cookie": "fc=rqbE3Poup4Ofv8GxDEGHJ0T2mPet6qErhzJbX2aX0FVY8uK-xitYHevMNKV5qRPTQHHOFrDBExLyIrZ-jLRD_r3wc-cQ7FRKnITKYzO3zYV52dhK4dSErN9-EcLOAtq0; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:48 GMT; Path=/" + }, + { + "content-type": "text/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:29:47 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "private, no-cache, no-store, must-revalidate" + }, + { + "date": "Sat, 03 Nov 2012 13:29:48 GMT" + }, + { + "content-length": "4142" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "cache-control": "private, max-age=0, no-cache, no-store, must-revalidate, proxy-revalidate" + }, + { + "expires": "Sat, 1 Jan 2000 01:01:00 GMT" + }, + { + "last-modified": "Sat, 1 Jan 2000 01:01:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "AdifyServer" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "45" + }, + { + "set-cookie": "s=1,2*50951c4c*3Q4liHxMwG*rZye1ewDYpnkdvSJkze6tOMY_w==*; path=/; expires=Mon, 03-Nov-2014 13:29:48 GMT; domain=afy11.net;" + }, + { + "p3p": "policyref=\"http://ad.afy11.net/privacy.xml\", CP=\" NOI DSP NID ADMa DEVa PSAa PSDa OUR OTRa IND COM NAV STA OTC\"" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "sess=1; path=/; expires=Sun, 04-Nov-2012 13:29:49 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "location": "http://r.turn.com/r/bd?ddc=1&pid=54&cver=1&uid=3755642153863499992" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + }, + { + "content-length": "0" + }, + { + "content-type": "text/html; charset=ISO-8859-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "GlassFish v3" + }, + { + "p3p": "policyref=\"/bh/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa DEVa PSAa OUR BUS COM NAV INT\"" + }, + { + "set-cookie": "pb_rtb_ev=2-535461.3194305635051091579.0.0.1351949514647; Domain=.contextweb.com; Expires=Sun, 03-Nov-2013 13:31:54 GMT; Path=/" + }, + { + "cw-server": "lga-app602" + }, + { + "cache-control": "private, max-age=0, no-cache, no-store" + }, + { + "expires": "-1" + }, + { + "content-type": "image/gif;charset=ISO-8859-1" + }, + { + "content-language": "en-US" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:31:54 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "cache-control": "post-check=0, pre-check=0" + }, + { + "content-location": "partner.html" + }, + { + "content-type": "text/html" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + }, + { + "expires": "Mon, 26 Jul 1997 05:00:00 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:29:49 GMT" + }, + { + "location": "http://cdn.spotxchange.com/media/thumbs/pixel/pixel.gif" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR IND UNI COM NAV ADMa\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8e-fips-rhel5" + }, + { + "set-cookie": "partner-0=eNptzM0KgkAUQOF1vUvgzzCF0MJwkpGuF3WyGXcpBKOZLYLJ%2B%2FRJtGx7OHyc7fxVdOBsU4lSxifZiCQyaiJ8vAh7EaLNnNGZ1471rMOaGp3dmvTomUpuO5ocWmkxBA4q5nKsWZfeZ6PLZxswi8GwdAigh3dOwFB9Tf%2Bfeb0UP2fgcvlRFQTJOQA6u1wJh0r4OQ3L4%2B3XH6c7OqM%3D; expires=Sun, 03-Mar-2013 13:29:49 GMT; path=/; domain=.spotxchange.com" + }, + { + "tcn": "choice" + }, + { + "vary": "negotiate" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "location": "http://r.turn.com/r/cms/id/0/ddc/1/pid/18/uid/?google_gid=CAESEITR3tLElIgxNs25jzV8Md0&google_cver=1" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "server": "Cookie Matcher" + }, + { + "content-length": "300" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + }, + { + "server": "Apache" + }, + { + "cache-control": "public, max-age=30, proxy-revalidate" + }, + { + "expires": "Mon, 26 Jul 1997 05:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "CP=\"CUR ADM OUR NOR STA NID\"" + }, + { + "set-cookie": "i=cbdc52da-b3d4-4f79-bc70-3121d006fdfa; expires=Mon, 03-Nov-2014 13:29:49 GMT; path=/; domain=.openx.net" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + }, + { + "server": "Apache/2.2.3 (CentOS)" + }, + { + "x-powered-by": "PHP/5.3.3" + }, + { + "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "set-cookie": "put_1185=3194305635051091579; expires=Wed, 02-Jan-2013 13:29:49 GMT; path=/; domain=.rubiconproject.com" + }, + { + "content-length": "49" + }, + { + "keep-alive": "timeout=30, max=9907" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + }, + { + "server": "Apache/2.2.22 (Ubuntu)" + }, + { + "x-powered-by": "PHP/5.3.10-1ubuntu3.4" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, max-age=0, no-cache, max-age=86400, must-revalidate" + }, + { + "p3p": "CP=\"CUR ADM OUR NOR STA NID\"" + }, + { + "set-cookie": "ljtrtb=eJyrVjJUslIyNrQ0MTYwNTM2NTA1NLA0NDW3VKoFAE9vBcg%3D; expires=Sun, 03-Nov-2013 13:29:49 GMT; path=/; domain=.lijit.com" + }, + { + "content-length": "43" + }, + { + "expires": "Sun, 04 Nov 2012 13:29:49 GMT" + }, + { + "connection": "close" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:48 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:49 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:49 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:49 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "adaptv/1.0" + }, + { + "content-type": "image/gif" + }, + { + "connection": "Keep-Alive" + }, + { + "set-cookie": "rtbData0=\"key=turn:value=3194305635051091579:expiresAt=Sat+Nov+10+05%3A29%3A49+PST+2012:32-Compatible=true\";Path=/;Domain=.adap.tv;Expires=Mon, 03-Nov-2014 13:29:49 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "W/\"21947-1351808321000\"" + }, + { + "last-modified": "Thu, 01 Nov 2012 22:18:41 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "21947" + }, + { + "date": "Sat, 03 Nov 2012 13:29:48 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:49 GMT" + }, + { + "server": "Apache/2.2.4 (Unix) DAV/2 mod_ssl/2.2.4 OpenSSL/0.9.7a mod_fastcgi/2.4.2" + }, + { + "set-cookie": "PUBRETARGET=82_1446557389; domain=pubmatic.com; expires=Tue, 03-Nov-2015 13:29:49 GMT; path=/" + }, + { + "content-length": "1" + }, + { + "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\"" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 26 May 2011 15:59:36 UTC" + }, + { + "content-length": "43" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "max-age=182357" + }, + { + "date": "Sat, 03 Nov 2012 13:29:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "content-type": "image/gif" + }, + { + "expires": "Sat, 03 Nov 2012 13:29:50 GMT" + }, + { + "cache-control": "max-age=0, no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "date": "Sat, 03 Nov 2012 13:29:50 GMT" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "set-cookie": "CMDD=;domain=casalemedia.com;path=/;expires=Sun, 04 Nov 2012 13:29:50 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "p3p": "policyref=\"http://tag.admeld.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR BUS DSP ALL COR\"" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-store" + }, + { + "expires": "Mon, 26 Jul 1997 05:00:00 GMT" + }, + { + "content-length": "35" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:29:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "none" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:29:50 GMT" + }, + { + "expires": "Mon, 26 Jul 1997 05:00:00 GMT" + }, + { + "p3p": "policyref=\"http://files.adbrite.com/w3c/p3p.xml\",CP=\"NOI PSA PSD OUR IND UNI NAV DEM STA OTC\"" + }, + { + "server": "XPEHb/1.2" + }, + { + "set-cookie": "rb2=CiQKBjc0MjY5Nxjxxt_6vwEiEzMxOTQzMDU2MzUwNTEwOTE1NzkQAQ; path=/; domain=.adbrite.com; expires=Fri, 01-Feb-2013 13:29:50 GMT" + }, + { + "content-length": "59" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "none" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:29:50 GMT" + }, + { + "expires": "Mon, 26 Jul 1997 05:00:00 GMT" + }, + { + "p3p": "policyref=\"http://files.adbrite.com/w3c/p3p.xml\",CP=\"NOI PSA PSD OUR IND UNI NAV DEM STA OTC\"" + }, + { + "server": "XPEHb/1.2" + }, + { + "set-cookie": "rb2=CiUKBzExMTM4NzQY78bf-r8BIhMzMTk0MzA1NjM1MDUxMDkxNTc5EAE; path=/; domain=.adbrite.com; expires=Fri, 01-Feb-2013 13:29:50 GMT" + }, + { + "content-length": "59" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-aspnetmvc-version": "4.0" + }, + { + "x-ua-compatible": "IE=Edge;chrome=1" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Sat, 03 Nov 2012 13:29:51 GMT" + }, + { + "content-length": "24328" + }, + { + "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"951751d2bdb7cd1:0\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "text/css" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"809c1885b2cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "7723" + }, + { + "age": "717364" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 16:35:09 GMT" + }, + { + "expires": "Sat, 26 Oct 2013 06:13:48 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "application/javascript" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"08343346b2cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "11495" + }, + { + "age": "717363" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 16:39:58 GMT" + }, + { + "expires": "Sat, 26 Oct 2013 06:13:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001003" + }, + { + "date": "Sat, 03 Nov 2012 13:29:51 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"4bbce916b2cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "10962" + }, + { + "age": "717363" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 16:38:33 GMT" + }, + { + "expires": "Sat, 26 Oct 2013 06:13:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/png" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"cf3edfd75b2cd1:0\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "2004" + }, + { + "age": "717364" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "last-modified": "Wed, 24 Oct 2012 16:37:22 GMT" + }, + { + "expires": "Sat, 26 Oct 2013 06:13:48 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "content-length": "955" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "2008" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=309678" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "26369" + }, + { + "age": "62302" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 10:12:48 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001004" + }, + { + "date": "Sat, 03 Nov 2012 13:29:51 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430622" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "45394" + }, + { + "age": "62302" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:48:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG5+^Cxrx)0s]#%2L_'x%SEV/hnK]14FQV_eKj?9AMF4:V)4hY/82QjU'-Rw1k^WD2#$i1)erK!!*m?S=+svq; path=/; expires=Fri, 01-Feb-2013 13:29:52 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "content-length": "1391" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "must-revalidate" + }, + { + "expires": "Mon, 05 Nov 2012 13:29:52 GMT" + }, + { + "set-cookie": "fc=PwF5GJAr9THO6EaVkyk6nl6s2gAVQMeB09yelt5Ns41Y8uK-xitYHevMNKV5qRPT6cGxTnB2KJjyGGqZV9P7973wc-cQ7FRKnITKYzO3zYV52dhK4dSErN9-EcLOAtq0; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:52 GMT; Path=/" + }, + { + "content-type": "text/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "set-cookie": "p=1-dPmPP55J4f0S;Path=/;Domain=.rfihub.com" + }, + { + "location": "http://ib.adnxs.com/pxj?bidder=18&seg=378601&action=setuids('672725195243299649','');&redir=" + }, + { + "content-length": "0" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG7DHCxrx)0s]#%2L_'x%SEV/hnK)x4FQV_eKj?9AMF4:V)4hY/82QjU'-Rw1k^WD2#$i1)erM67KPze!'cEZmBiRY; path=/; expires=Fri, 01-Feb-2013 13:29:52 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-length": "43" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/json; charset=utf-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "private, no-cache, no-store, must-revalidate" + }, + { + "date": "Sat, 03 Nov 2012 13:29:52 GMT" + }, + { + "content-length": "4142" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:53 GMT" + }, + { + "location": "http://dpm.demdex.net/ibs:dpid=375&dpuuid=3194305635051091579" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:53 GMT" + }, + { + "location": "http://tags.bluekai.com/site/4499?id=3194305635051091579" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:53 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:53 GMT" + }, + { + "connection": "close" + }, + { + "server": "AAWebServer" + }, + { + "p3p": "policyref=\"http://www.adadvisor.net/w3c/p3p.xml\",CP=\"NOI NID\"" + }, + { + "content-length": "21" + }, + { + "content-type": "application/javascript" + }, + { + "set-cookie": "ab=0001%3ATeN7H043oXvJ0Gd0I9Rzik4yxpbxTv3S; Domain=.adadvisor.net; Expires=Sat, 03 Nov 2013 13:29:53 GMT; Path=/" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI NID CURa ADMa DEVa PSAa PSDa OUR SAMa BUS PUR COM NAV INT\"" + }, + { + "dcs": "la-dcs-3-1.internal.demdex.com 1.9.12" + }, + { + "set-cookie": "demdex=24048888904140259620062165691276314735;Path=/;Domain=.demdex.net;Expires=Thu, 03-Nov-2022 23:37:33 GMT" + }, + { + "expires": "Thu, 01 Jan 2009 00:00:00 GMT" + }, + { + "cache-control": "no-cache,no-store,must-revalidate,max-age=0,proxy-revalidate,no-transform,private" + }, + { + "pragma": "no-cache" + }, + { + "location": "http://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=375&dpuuid=3194305635051091579" + }, + { + "content-length": "0" + }, + { + "server": "Jetty(7.2.2.v20101205)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI NID CURa ADMa DEVa PSAa PSDa OUR SAMa BUS PUR COM NAV INT\"" + }, + { + "dcs": "la-dcs-6-3.internal.demdex.com 1.9.12" + }, + { + "set-cookie": "dpm=24048888904140259620062165691276314735;Path=/;Domain=.dpm.demdex.net;Expires=Thu, 03-Nov-2022 23:37:33 GMT" + }, + { + "expires": "Thu, 01 Jan 2009 00:00:00 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "no-cache,no-store,must-revalidate,max-age=0,proxy-revalidate,no-transform,private" + }, + { + "pragma": "no-cache" + }, + { + "sts": "OK" + }, + { + "content-length": "308" + }, + { + "server": "Jetty(7.2.2.v20101205)" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/" + }, + { + "location": "http://segment-pixel.invitemedia.com/set_partner_uid?partnerID=402&sscs_active=1&partnerUID=3194305635051091579" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:29:53 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/" + }, + { + "location": "http://dpm.demdex.net/ibs:dpid=470&dpuuid=3194305635051091579" + }, + { + "transfer-encoding": "chunked" + }, + { + "date": "Sat, 03 Nov 2012 13:29:53 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI NID CURa ADMa DEVa PSAa PSDa OUR SAMa BUS PUR COM NAV INT\"" + }, + { + "dcs": "la-dcs-6-4.internal.demdex.com 1.9.12" + }, + { + "set-cookie": "dpm=24048888904140259620062165691276314735;Path=/;Domain=.dpm.demdex.net;Expires=Thu, 03-Nov-2022 23:37:33 GMT" + }, + { + "expires": "Thu, 01 Jan 2009 00:00:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "no-cache,no-store,must-revalidate,max-age=0,proxy-revalidate,no-transform,private" + }, + { + "pragma": "no-cache" + }, + { + "sts": "OK" + }, + { + "content-length": "42" + }, + { + "server": "Jetty(7.2.2.v20101205)" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:29:53 GMT" + }, + { + "set-cookie": "io_frequency=;Path=/;Domain=invitemedia.com;Expires=Thu, 01-Jan-1970 00:00:01 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"OTI DSP COR ADMo TAIo PSAo PSDo CONo OUR SAMo OTRo STP UNI PUR COM NAV INT DEM STA PRE LOC\"" + }, + { + "cache-control": "no-cache" + }, + { + "location": "http://cm.g.doubleclick.net/pixel?google_nid=invitemedia&google_cm&google_hm=ZGdnc8YbR_itxPPM3K8lNw==" + }, + { + "content-length": "0" + }, + { + "connection": "close" + }, + { + "server": "Jetty(7.3.1.v20110307)" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "location": "http://g-pixel.invitemedia.com/gmatcher?google_gid=CAESEIZ7yBsa025UuJ5EUDIscrc&google_cver=1" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "server": "Cookie Matcher" + }, + { + "content-length": "293" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "set-cookie": "io_frequency=;Path=/;Domain=invitemedia.com;Expires=Thu, 01-Jan-1970 00:00:01 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"OTI DSP COR ADMo TAIo PSAo PSDo CONo OUR SAMo OTRo STP UNI PUR COM NAV INT DEM STA PRE LOC\"" + }, + { + "cache-control": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "server": "Jetty(7.3.1.v20110307)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3512552298351731296; Domain=.audienceiq.com; Expires=Thu, 02-May-2013 13:29:54 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:53 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3819163497929337273; Domain=.audienceiq.com; Expires=Thu, 02-May-2013 13:29:54 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "server": "Apache/2.2.3 (CentOS)" + }, + { + "p3p": "CP=\"NOI DSP COR CUR ADMo DEVo PSAo PSDo OUR SAMo BUS UNI NAV\", policyref=\"http://tags.bluekai.com/w3c/p3p.xml\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "max-age=0, no-cache, no-store" + }, + { + "set-cookie": "bkdc=wdc; expires=Mon, 03-Dec-2012 13:29:54 GMT; path=/; domain=.bluekai.com" + }, + { + "bk-server": "f325" + }, + { + "content-length": "62" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430617" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "49975" + }, + { + "age": "62304" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:48:27 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=402248" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "54206" + }, + { + "age": "62304" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 11:55:38 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=404329" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "34129" + }, + { + "age": "62304" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 12:30:19 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430621" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "30171" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:48:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=424287" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "32018" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 18:02:58 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=427425" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "24185" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 18:55:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=272174" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "33943" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Mon, 05 Nov 2012 23:47:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=325871" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "52353" + }, + { + "age": "62304" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 14:42:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430158" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "29736" + }, + { + "age": "62304" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:40:48 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430924" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "16459" + }, + { + "age": "62304" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:53:34 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=392023" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "16888" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 09:05:14 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430621" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "39134" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:48:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430616" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "18663" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:48:27 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430616" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "22545" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:48:27 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=309680" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "48746" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 10:12:51 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=307453" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "32656" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 09:35:44 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431902" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "4473" + }, + { + "age": "16748" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 08:49:08 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=429492" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "5239" + }, + { + "age": "22750" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 06:28:56 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426970" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "4784" + }, + { + "age": "22751" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Thu, 08 Nov 2012 05:46:53 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431944" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "3843" + }, + { + "age": "50495" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 23:27:23 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431143" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "4058" + }, + { + "age": "50541" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 23:13:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431761" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "3291" + }, + { + "age": "84703" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 13:54:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430621" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "34459" + }, + { + "age": "62302" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:48:33 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:55 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:55 GMT" + }, + { + "content-length": "954" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "1996" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001006" + }, + { + "date": "Sat, 03 Nov 2012 13:29:55 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG4S]cvjr/?0P(*AuB-u**g1:XIFC`Ei'/AQwFYO^vhHR3SSI7:0ssX1ka!s@?zYs*/7]T1O`l^oQUpqMxHLk'kk[7/>IRq; path=/; expires=Fri, 01-Feb-2013 13:29:56 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:29:56 GMT" + }, + { + "content-length": "1447" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "must-revalidate" + }, + { + "expires": "Mon, 05 Nov 2012 13:29:56 GMT" + }, + { + "set-cookie": "fc=2flUeaaDSas8xOI0IwXvS5DprXaL8T8Iioo9PyFO3fRY8uK-xitYHevMNKV5qRPT3ar07KU0y6i_uQzRwZVJBr3wc-cQ7FRKnITKYzO3zYV52dhK4dSErN9-EcLOAtq0; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:56 GMT; Path=/" + }, + { + "content-type": "text/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:29:55 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001005" + }, + { + "date": "Sat, 03 Nov 2012 13:29:55 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001002" + }, + { + "date": "Sat, 03 Nov 2012 13:29:55 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=337125" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "47409" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Tue, 06 Nov 2012 17:50:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:55 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html;charset=UTF-8" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "private, no-cache, no-store, must-revalidate" + }, + { + "date": "Sat, 03 Nov 2012 13:29:56 GMT" + }, + { + "content-length": "4142" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430158" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "40464" + }, + { + "age": "62303" + }, + { + "date": "Sat, 03 Nov 2012 13:29:54 GMT" + }, + { + "expires": "Wed, 07 Nov 2012 19:40:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "p3p": "CP=\"NON DSP COR CURa PSA PSD OUR BUS NAV STA\"" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "date": "Sat, 03 Nov 2012 13:29:55 GMT" + }, + { + "content-length": "43" + }, + { + "vary": "Accept-Encoding" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:56 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:57 GMT" + }, + { + "content-length": "1162" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "2685" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10661134-T100558395-C70000000000110100" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001005" + }, + { + "date": "Sat, 03 Nov 2012 13:29:57 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001004" + }, + { + "date": "Sat, 03 Nov 2012 13:29:56 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001005" + }, + { + "date": "Sat, 03 Nov 2012 13:29:57 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-length": "2346" + }, + { + "date": "Sat, 03 Nov 2012 13:29:57 GMT" + }, + { + "location": "http://s0.2mdn.net/viewad/3642305/1-1x1.gif" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "server": "DCLK-AdSvr" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "last-modified": "Tue, 08 May 2012 20:09:07 GMT" + }, + { + "date": "Fri, 02 Nov 2012 14:30:09 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 14:30:09 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "321" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "82788" + }, + { + "cache-control": "public, max-age=86400" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 24 May 2012 20:12:56 GMT" + }, + { + "date": "Fri, 02 Nov 2012 20:51:00 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 20:51:00 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "16399" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "age": "59938" + }, + { + "cache-control": "public, max-age=86400" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:29:58 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:59 GMT" + }, + { + "content-length": "953" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "1996" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001006" + }, + { + "date": "Sat, 03 Nov 2012 13:29:58 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG2<rcvjr/?0P(*AuB-u**g1:XIB_LEi'/AQwFYO^vhHR3SSI7:0ssX1dkoAOc['^!Xu%1Q*<TAN0EGDS>RnOx8gy:7tmWz0W/8y; path=/; expires=Fri, 01-Feb-2013 13:29:59 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:29:59 GMT" + }, + { + "content-length": "539" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001005" + }, + { + "date": "Sat, 03 Nov 2012 13:29:58 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001003" + }, + { + "date": "Sat, 03 Nov 2012 13:29:59 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-msadid": "300089440.299934848" + }, + { + "date": "Sat, 03 Nov 2012 13:29:58 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "508" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:59 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:29:58 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:29:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:30:00 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:29:59 GMT" + }, + { + "content-length": "954" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "2008" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001005" + }, + { + "date": "Sat, 03 Nov 2012 13:29:59 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001004" + }, + { + "date": "Sat, 03 Nov 2012 13:29:59 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001001" + }, + { + "date": "Sat, 03 Nov 2012 13:30:00 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG6kGcvjr/?0P(*AuB-u**g1:XIDv6Ei'/AQwFYO^vhHR3SSI7:0ssX1dl0I/A@=2rt>+)p4?5?fIu<PZksk:x)IOr/*M`m)sza^*g0Y08QVgH; path=/; expires=Fri, 01-Feb-2013 13:30:00 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:30:00 GMT" + }, + { + "content-length": "536" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-msadid": "300089389.300024911" + }, + { + "date": "Sat, 03 Nov 2012 13:29:59 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "2292" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:30:00 GMT" + }, + { + "set-cookie": "io_frequency=;Path=/;Domain=invitemedia.com;Expires=Thu, 01-Jan-1970 00:00:01 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"OTI DSP COR ADMo TAIo PSAo PSDo CONo OUR SAMo OTRo STP UNI PUR COM NAV INT DEM STA PRE LOC\"" + }, + { + "cache-control": "no-cache" + }, + { + "content-length": "43" + }, + { + "connection": "close" + }, + { + "server": "Jetty(7.3.1.v20110307)" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:30:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:30:01 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "content-length": "954" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "2008" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001006" + }, + { + "date": "Sat, 03 Nov 2012 13:30:01 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001001" + }, + { + "date": "Sat, 03 Nov 2012 13:30:01 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001004" + }, + { + "date": "Sat, 03 Nov 2012 13:30:01 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG10Qcvjr/?0P(*AuB-u**g1:XICjmEi'/AQwFYO^vhHR3SSI7:0ssX1dl0I/A@=2rt>+)p4?5?fIu<PZksk:8=1cxYEkOC%bAiN80044UhHvz!%M]c5$rYZ; path=/; expires=Fri, 01-Feb-2013 13:30:02 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "content-length": "555" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + }, + { + "server": "mt2/2.6.2.2465 Sep 24 2012 22:21:34 ewr-pixel-x1 pid 0x7b39 31545" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\"" + }, + { + "set-cookie": "uuid=50951c5a-a617-32b8-be76-b1fea84d696f; domain=.mathtag.com; path=/; expires=Sun, 03-Nov-2013 13:30:02 GMT" + }, + { + "location": "http://sync.mathtag.com/sync/img?mt_exid=13&mt_exuid=3755642153863499992&mm_bnc" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-msadid": "300088980.299949017.299886085" + }, + { + "date": "Sat, 03 Nov 2012 13:30:01 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "2684" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "33683" + }, + { + "allow": "GET" + }, + { + "expires": "Fri, 09 Nov 2012 04:46:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "server": "mt2/2.6.2.2465 Sep 24 2012 22:21:34 ewr-pixel-x6 pid 0x3dc6 15814" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\"" + }, + { + "set-cookie": "mt_mop=13:1351949402|10002:1351949402; domain=.mathtag.com; path=/; expires=Mon, 03-Dec-2012 13:30:02 GMT" + }, + { + "location": "http://tags.bluekai.com/site/2948?id=50951c5a-a617-32b8-be76-b1fea84d696f" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:30:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "server": "Apache/2.2.3 (CentOS)" + }, + { + "p3p": "CP=\"NOI DSP COR CUR ADMo DEVo PSAo PSDo OUR SAMo BUS UNI NAV\", policyref=\"http://tags.bluekai.com/w3c/p3p.xml\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sun, 04 Nov 2012 13:30:02 GMT" + }, + { + "cache-control": "max-age=86400, private" + }, + { + "set-cookie": "bkdc=wdc; expires=Mon, 03-Dec-2012 13:30:02 GMT; path=/; domain=.bluekai.com" + }, + { + "bk-server": "ed3c" + }, + { + "content-length": "62" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001005" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001003" + }, + { + "date": "Sat, 03 Nov 2012 13:30:03 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001001" + }, + { + "date": "Sat, 03 Nov 2012 13:30:02 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:30:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "1996" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:30:03 GMT" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "954" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG5`$cvjr/?0P(*AuB-u**g1:XIF)WEi'/AQwFYO^vhHR3SSI7:0ssX1dl0I/A@=2rt>+)p4?5?fIu<PZksk:8=1cxY3czU+5<.*N0EGE.[oe!wqakQLnSHY42'_N; path=/; expires=Fri, 01-Feb-2013 13:30:03 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:30:03 GMT" + }, + { + "content-length": "534" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-msadid": "300089440.299934848" + }, + { + "date": "Sat, 03 Nov 2012 13:30:03 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "509" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI NID CURa ADMa DEVa PSAa PSDa OUR SAMa BUS PUR COM NAV INT\"" + }, + { + "dcs": "la-dcs-4-2.internal.demdex.com 1.9.12" + }, + { + "set-cookie": "dpm=24048888904140259620062165691276314735;Path=/;Domain=.dpm.demdex.net;Expires=Thu, 03-Nov-2022 23:37:33 GMT" + }, + { + "expires": "Thu, 01 Jan 2009 00:00:00 GMT" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "no-cache,no-store,must-revalidate,max-age=0,proxy-revalidate,no-transform,private" + }, + { + "pragma": "no-cache" + }, + { + "sts": "OK" + }, + { + "content-length": "42" + }, + { + "server": "Jetty(7.2.2.v20101205)" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "-1" + }, + { + "vary": "Accept-Encoding" + }, + { + "server": "Microsoft-IIS/8.0" + }, + { + "x-aspnetmvc-version": "4.0" + }, + { + "x-ua-compatible": "IE=Edge;chrome=1" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-frame-options": "SAMEORIGIN" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-content-type-options": "nosniff" + }, + { + "date": "Sat, 03 Nov 2012 13:30:04 GMT" + }, + { + "content-length": "26996" + }, + { + "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"951751d2bdb7cd1:0\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "private, no-cache, proxy-revalidate, no-store" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"04baaef128fcc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001005" + }, + { + "date": "Sat, 03 Nov 2012 13:30:04 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, must-revalidate" + }, + { + "content-type": "text/html; Charset=utf-8" + }, + { + "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"01c35bc2fa3cd1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "access-control-allow-origin": "*" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "content-length": "954" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "2008" + }, + { + "expires": "Fri, 01 Jan 1990 00:00:00 GMT" + }, + { + "x-radid": "P10723443-T100550693-C29000000000082620" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426988" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "27953" + }, + { + "age": "303593" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 23:46:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=416068" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "42814" + }, + { + "age": "303593" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 20:44:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache, no-store, must-revalidate" + }, + { + "pragma": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "expires": "-1" + }, + { + "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "etag": "\"a29327667d45cc1:0\"" + }, + { + "server": "Microsoft-IIS/7.5" + }, + { + "s": "VIEMSNVM001002" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "content-length": "42" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store, no-cache, private" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Sat, 15 Nov 2008 16:00:00 GMT" + }, + { + "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\"" + }, + { + "x-xss-protection": "0" + }, + { + "set-cookie": "anj=Kfu=8fG3H<cvjr/?0P(*AuB-u**g1:XIC8]Ei'/AQwFYO^vhHR3SSI7:0ssX1dl0I/A@=2rt>+)p4?5?fIu<PZksk:^@W+Nwgwmo%ACvi+5<.*N0Iu+9Y'W#w3TL$v$Kfc5PKO+; path=/; expires=Fri, 01-Feb-2013 13:30:05 GMT; domain=.adnxs.com; HttpOnly" + }, + { + "content-type": "text/html; charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "content-length": "607" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "server": "Jetty(6.1.22)" + }, + { + "set-cookie": "wfivefivec=8293faeb-8917-4006-95bc-2d52d4cd2f6d;Path=/;Domain=.w55c.net;Expires=Mon, 03-Nov-14 13:30:06 GMT" + }, + { + "p3p": "policyref=\"https://cts.w55c.net/ct/p3p_policy_ref.xml\", CP=\"UNI PUR COM INT STA OTC STP OUR CUR TAIo COR DSP NOI\"" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "image/gif" + }, + { + "x-powered-by": "Mirror Image Internet" + }, + { + "content-length": "42" + }, + { + "via": "1.1 ttn061005 (MII-APC/2.2)" + }, + { + "keep-alive": "timeout=2" + }, + { + "connection": "Keep-Alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-store" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "0" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-msadid": "300089440.299934848" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "connection": "close" + }, + { + "content-length": "511" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/json; charset=utf-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-length": "35" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "content-length": "0" + }, + { + "date": "Sat, 03 Nov 2012 13:30:05 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Mon, 01 Jan 1990 00:00:00 GMT" + }, + { + "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=418020" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "41311" + }, + { + "age": "303593" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 21:17:13 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426681" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "47495" + }, + { + "age": "303593" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 23:41:34 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431985" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA08" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA08" + }, + { + "content-length": "26998" + }, + { + "age": "385360" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 02:27:11 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431851" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA06" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA06" + }, + { + "content-length": "27541" + }, + { + "age": "327876" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 18:23:01 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431570" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "40200" + }, + { + "age": "303592" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Mon, 05 Nov 2012 01:03:04 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426988" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "31967" + }, + { + "age": "303593" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 23:46:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431525" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "45843" + }, + { + "age": "303592" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Mon, 05 Nov 2012 01:02:19 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431595" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA07" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA07" + }, + { + "content-length": "41590" + }, + { + "age": "303593" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Mon, 05 Nov 2012 01:03:28 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426365" + }, + { + "content-type": "image/jpeg" + }, + { + "server": "CO1MPPSTCA05" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\"" + }, + { + "s": "CO1MPPSTCA05" + }, + { + "content-length": "46706" + }, + { + "age": "303593" + }, + { + "date": "Sat, 03 Nov 2012 13:30:06 GMT" + }, + { + "expires": "Sun, 04 Nov 2012 23:36:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_30.json b/jetty-http2/http2-hpack/src/test/resources/data/story_30.json new file mode 100644 index 00000000000..6ecb39dc312 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_30.json @@ -0,0 +1,28257 @@ +{ + "context": "response", + "cases": [ + { + "headers": [ + { + ":status": "302" + }, + { + "date": "Sat, 03 Nov 2012 13:39:05 GMT" + }, + { + "server": "Apache" + }, + { + "location": "http://www.nytimes.com/" + }, + { + "content-length": "207" + }, + { + "connection": "close" + }, + { + "content-type": "text/html; charset=iso-8859-1" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:05 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:05 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 02 Oct 2012 23:33:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1054" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=242" + }, + { + "expires": "Sat, 03 Nov 2012 13:43:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "915" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=75412" + }, + { + "expires": "Sun, 04 Nov 2012 10:35:58 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "563" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=75368" + }, + { + "expires": "Sun, 04 Nov 2012 10:35:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Thu, 11 Oct 2012 13:17:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "5433" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=71334" + }, + { + "expires": "Sun, 04 Nov 2012 09:28:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 02 Oct 2012 23:33:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11190" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=255" + }, + { + "expires": "Sat, 03 Nov 2012 13:43:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:01:02 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "414" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=124" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 12 Oct 2012 00:30:38 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1460" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=141" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "593" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=75423" + }, + { + "expires": "Sun, 04 Nov 2012 10:36:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 12 Oct 2012 00:30:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "14014" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=181" + }, + { + "expires": "Sat, 03 Nov 2012 13:42:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 11 Oct 2012 13:32:22 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2864" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=71377" + }, + { + "expires": "Sun, 04 Nov 2012 09:28:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 15:09:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1204" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=41140" + }, + { + "expires": "Sun, 04 Nov 2012 01:04:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 14 Sep 2011 21:26:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1330" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=249513" + }, + { + "expires": "Tue, 06 Nov 2012 10:57:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Thu, 28 Jun 2012 19:00:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1261" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=249513" + }, + { + "expires": "Tue, 06 Nov 2012 10:57:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Mar 2012 17:13:25 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "33140" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=121" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 14:49:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "75" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=348760" + }, + { + "expires": "Wed, 07 Nov 2012 14:31:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "769" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=63729" + }, + { + "expires": "Sun, 04 Nov 2012 07:21:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 24 Oct 2012 22:07:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2335" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=501801" + }, + { + "expires": "Fri, 09 Nov 2012 09:02:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 05 Jun 2012 14:20:01 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5065" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=139006" + }, + { + "expires": "Mon, 05 Nov 2012 04:15:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 18:30:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9619" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=449914" + }, + { + "expires": "Thu, 08 Nov 2012 18:37:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 22:09:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9453" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=463322" + }, + { + "expires": "Thu, 08 Nov 2012 22:21:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:05 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "RMID=007f010022166047bee9002b; Expires=Sun, 03 Nov 2013 13:39:05 GMT; Path=/; Domain=.nytimes.com;" + }, + { + "set-cookie": "adxcs=-; path=/; domain=.nytimes.com" + }, + { + "vary": "Host" + }, + { + "cteonnt-length": "174626" + }, + { + "connection": "close" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 02 Nov 2012 20:52:54 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "10651" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=548063" + }, + { + "expires": "Fri, 09 Nov 2012 21:53:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 00:08:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9713" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=481042" + }, + { + "expires": "Fri, 09 Nov 2012 03:16:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 13 Sep 2012 21:58:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "13397" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=50108" + }, + { + "expires": "Sun, 04 Nov 2012 03:34:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 14:25:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10596" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=43276" + }, + { + "expires": "Sun, 04 Nov 2012 01:40:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 13 Sep 2012 21:58:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "857" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=50108" + }, + { + "expires": "Sun, 04 Nov 2012 03:34:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 22:20:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "23526" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=60" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:26:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9473" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=551938" + }, + { + "expires": "Fri, 09 Nov 2012 22:58:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:54:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5048" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=63748" + }, + { + "expires": "Sun, 04 Nov 2012 07:21:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 14:49:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3428" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=348719" + }, + { + "expires": "Wed, 07 Nov 2012 14:31:05 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 22:24:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9374" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=550656" + }, + { + "expires": "Fri, 09 Nov 2012 22:36:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 01:15:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9656" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=561534" + }, + { + "expires": "Sat, 10 Nov 2012 01:38:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:27:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "10211" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=564327" + }, + { + "expires": "Sat, 10 Nov 2012 02:24:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:03:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9722" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568295" + }, + { + "expires": "Sat, 10 Nov 2012 03:30:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 23:51:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9372" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=555580" + }, + { + "expires": "Fri, 09 Nov 2012 23:58:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Oct 2012 17:14:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "22786" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=559540" + }, + { + "expires": "Sat, 10 Nov 2012 01:04:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "content-type": "text/html" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 01:28:33 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9942" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=564328" + }, + { + "expires": "Sat, 10 Nov 2012 02:24:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:54:41 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9364" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568578" + }, + { + "expires": "Sat, 10 Nov 2012 03:35:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 03 Nov 2012 06:09:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9404" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=578228" + }, + { + "expires": "Sat, 10 Nov 2012 06:16:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 22:38:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10217" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=478523" + }, + { + "expires": "Fri, 09 Nov 2012 02:34:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 01:19:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9052" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568307" + }, + { + "expires": "Sat, 10 Nov 2012 03:30:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 23:00:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9379" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=553121" + }, + { + "expires": "Fri, 09 Nov 2012 23:17:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:02:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9989" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=538058" + }, + { + "expires": "Fri, 09 Nov 2012 19:06:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Thu, 01 Nov 2012 22:36:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "10950" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=531474" + }, + { + "expires": "Fri, 09 Nov 2012 17:17:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 16:22:38 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11381" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=529651" + }, + { + "expires": "Fri, 09 Nov 2012 16:46:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 18:00:09 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10322" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=534703" + }, + { + "expires": "Fri, 09 Nov 2012 18:10:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 17:11:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "22643" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=537513" + }, + { + "expires": "Fri, 09 Nov 2012 18:57:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:59:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8617" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=459081" + }, + { + "expires": "Thu, 08 Nov 2012 21:10:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:29:35 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10164" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=539911" + }, + { + "expires": "Fri, 09 Nov 2012 19:37:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 02 Nov 2012 05:22:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9476" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=488920" + }, + { + "expires": "Fri, 09 Nov 2012 05:27:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 22:29:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9077" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=551868" + }, + { + "expires": "Fri, 09 Nov 2012 22:56:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 17:43:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10600" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=540450" + }, + { + "expires": "Fri, 09 Nov 2012 19:46:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 20:32:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9896" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=547139" + }, + { + "expires": "Fri, 09 Nov 2012 21:38:05 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 15:09:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "572" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=41141" + }, + { + "expires": "Sun, 04 Nov 2012 01:04:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Tue, 28 Apr 2009 18:18:22 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "404" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=41148" + }, + { + "expires": "Sun, 04 Nov 2012 01:04:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 Sep 2012 11:12:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2845" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=63810" + }, + { + "expires": "Sun, 04 Nov 2012 07:22:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 13 Sep 2012 16:49:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3246" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=64066" + }, + { + "expires": "Sun, 04 Nov 2012 07:26:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 22:45:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "18527" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=51883" + }, + { + "expires": "Sun, 04 Nov 2012 04:03:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "402" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=61804" + }, + { + "expires": "Sun, 04 Nov 2012 06:49:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1108" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=33319" + }, + { + "expires": "Sat, 03 Nov 2012 22:54:25 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 14 May 2010 14:50:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "3113" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=250845" + }, + { + "expires": "Tue, 06 Nov 2012 11:19:51 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "132" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=82000" + }, + { + "expires": "Sun, 04 Nov 2012 12:25:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "130" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=44124" + }, + { + "expires": "Sun, 04 Nov 2012 01:54:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 12:22:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2027" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=141" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5636" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39613" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:57:18 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9333" + }, + { + "nncoection": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592839" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:04:47 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "12380" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=574165" + }, + { + "expires": "Sat, 10 Nov 2012 05:08:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 03:51:38 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "14526" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=574163" + }, + { + "expires": "Sat, 10 Nov 2012 05:08:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 09:37:18 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "27338" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592839" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 03:21:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "17678" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=574163" + }, + { + "expires": "Sat, 10 Nov 2012 05:08:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "15086" + }, + { + "content-type": "image/x-icon" + }, + { + "cache-control": "private, max-age=47723" + }, + { + "expires": "Sun, 04 Nov 2012 02:54:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 15 Oct 2012 20:38:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "14119" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=38721" + }, + { + "expires": "Sun, 04 Nov 2012 00:24:27 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 11 Oct 2012 22:23:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "15038" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=77030" + }, + { + "expires": "Sun, 04 Nov 2012 11:02:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "15051" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39616" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 03:52:36 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9914" + }, + { + "nncoection": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=574165" + }, + { + "expires": "Sat, 10 Nov 2012 05:08:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:26:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "13388" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=574135" + }, + { + "expires": "Sat, 10 Nov 2012 05:08:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:54:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=45924" + }, + { + "expires": "Sun, 04 Nov 2012 02:24:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:06 GMT" + }, + { + "content-length": "73046" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39601" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:15 GMT" + }, + { + "content-length": "1713" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:26:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1246" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=45118" + }, + { + "expires": "Sun, 04 Nov 2012 02:11:13 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:15 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9877" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39601" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:15 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "328" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=63772" + }, + { + "expires": "Sun, 04 Nov 2012 07:22:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:39:16 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=0F8E3E619FFB422270FEEB659AA60437&e=i.1354338000&t=i.10&v=i.0&l=l.25.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.0.0.0.0&pr=l.4.1.0.0.0&vp=i.0&gf=l.10.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:16 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "114" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "424" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=81965" + }, + { + "expires": "Sun, 04 Nov 2012 12:25:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:16 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "504" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=81965" + }, + { + "expires": "Sun, 04 Nov 2012 12:25:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 25 Mar 2011 19:37:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "68" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=1088067" + }, + { + "expires": "Fri, 16 Nov 2012 03:53:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 25 Mar 2011 19:37:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "3422" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=279280" + }, + { + "expires": "Tue, 06 Nov 2012 19:13:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:16 GMT" + }, + { + "connection": "keep-alive" + }, + { + "nncoection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "368" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=82007" + }, + { + "expires": "Sun, 04 Nov 2012 12:26:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39602" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:16 GMT" + }, + { + "content-length": "8728" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:48:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7020" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39602" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 14:49:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "193" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=349609" + }, + { + "expires": "Wed, 07 Nov 2012 14:46:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 15:30:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "193" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=349609" + }, + { + "expires": "Wed, 07 Nov 2012 14:46:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Feb 2010 03:33:33 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "192" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=349609" + }, + { + "expires": "Wed, 07 Nov 2012 14:46:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 14:49:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "192" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=349609" + }, + { + "expires": "Wed, 07 Nov 2012 14:46:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:50:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "35113" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592829" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:48:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "29467" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592829" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:51:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "16823" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592829" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "550" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=82007" + }, + { + "expires": "Sun, 04 Nov 2012 12:26:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:52:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "16912" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592829" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:49:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "25024" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592829" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:49:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "24454" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592829" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:50:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "30450" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592829" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:51:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "19300" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=592829" + }, + { + "expires": "Sat, 10 Nov 2012 10:19:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Oct 2012 12:34:42 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10032" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=536866" + }, + { + "expires": "Fri, 09 Nov 2012 18:47:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 03 Nov 2012 03:00:09 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9307" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=566721" + }, + { + "expires": "Sat, 10 Nov 2012 03:04:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:58:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9354" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573743" + }, + { + "expires": "Sat, 10 Nov 2012 05:01:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 08 Jun 2012 19:24:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "49" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=349611" + }, + { + "expires": "Wed, 07 Nov 2012 14:46:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "access-control-allow-origin": "*" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-type": "text/html" + }, + { + "content-length": "4654" + }, + { + "set-cookie": "PRpc=|HwqgHD3W:1|HrYwHDG0:1|HrYvHDG1:2|#;domain=ads.pointroll.com; path=/; expires=Mon, 03-Nov-2014 13:39:17 GMT;" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "186" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=72083" + }, + { + "expires": "Sun, 04 Nov 2012 09:40:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "46" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=45062" + }, + { + "expires": "Sun, 04 Nov 2012 02:10:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "188" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=80765" + }, + { + "expires": "Sun, 04 Nov 2012 12:05:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "74" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=45140" + }, + { + "expires": "Sun, 04 Nov 2012 02:11:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "text/javascript" + }, + { + "cache-control": "max-age=1200" + }, + { + "etag": "\"4c3fb0afe8567a750ed2a0ea49e6944fba16bf00\"" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-served-by": "apiservices-a004.krxd.net" + }, + { + "x-request-backend": "controltag" + }, + { + "x-config-age": "400" + }, + { + "x-cache-hits": "103" + }, + { + "x-age": "377" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "content-length": "26341" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "64" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=49385" + }, + { + "expires": "Sun, 04 Nov 2012 03:22:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "content-type": "text/html" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 05 Oct 2012 17:38:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2153" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=35030" + }, + { + "expires": "Sat, 03 Nov 2012 23:23:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "159" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "content-type": "text/html" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "5623" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:27:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "35" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=82032" + }, + { + "expires": "Sun, 04 Nov 2012 12:26:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:16 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Tue, 01 Mar 2011 22:54:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "2078" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=279283" + }, + { + "expires": "Tue, 06 Nov 2012 19:14:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "nncoection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 03 Mar 2011 19:32:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "593" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=279282" + }, + { + "expires": "Tue, 06 Nov 2012 19:14:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "nncoection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 03 Mar 2011 19:32:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1062" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=279282" + }, + { + "expires": "Tue, 06 Nov 2012 19:14:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "nncoection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 03 Mar 2011 19:32:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "830" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=279285" + }, + { + "expires": "Tue, 06 Nov 2012 19:14:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "nncoection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 14 Nov 2011 19:12:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1230" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=310332" + }, + { + "expires": "Wed, 07 Nov 2012 03:51:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "46" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=49385" + }, + { + "expires": "Sun, 04 Nov 2012 03:22:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "nncoection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 03 Mar 2011 19:32:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "319" + }, + { + "nncoection": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=279282" + }, + { + "expires": "Tue, 06 Nov 2012 19:14:00 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:18 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-type": "application/x-javascript" + }, + { + "content-length": "65" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "cache-control": "no-cache" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1968" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39604" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs37lVrcF5/ZLq6rynLbPIrYKIQNSvBay5eXmklcaqTTiLoOeuQVXo/ErioUh8fUwMfecUglqHQguFB4PZbqjfC/R139oOkeO9km0JPhPmAlXHZdbK2WUEIbFJNiFPRmQDogdoIloef2Ff8AdiQTdLWj97qwBkClC8B/JlbaEoMNL360/5sp2oAT08Y; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:18 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas02-12" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:19 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39604" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "content-length": "11292" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "x-amz-id-2": "DlMsa95OAPS0ALn9DdiKGfdHovCM2TvJb0VQCd4x9FF44D35U9YbOWNnUKKYQL89" + }, + { + "x-amz-request-id": "8987CB21B2CF98CC" + }, + { + "date": "Sat, 03 Nov 2012 13:39:20 GMT" + }, + { + "cache-control": "max-age=10" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:35:29 GMT" + }, + { + "etag": "\"8254326a395317db7b197564fa83e476\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "" + }, + { + "content-length": "92155" + }, + { + "server": "AmazonS3" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39603" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:19 GMT" + }, + { + "content-length": "645" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6174" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=39603" + }, + { + "expires": "Sun, 04 Nov 2012 00:39:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:19 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "303" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:19 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "location": "/dcsa5pgfq10000c9zuysqk0lm_6i8y/dcs.gif?dcsredirect=126&dcstlh=0&dcstlv=0&dcsdat=1351949959619&dcssip=www.nytimes.com&dcsuri=/&WT.co_f=130.129.68.73-2680109824.30259656&WT.vt_sid=130.129.68.73-2680109824.30259656.1351949959620&WT.vt_f_tlv=0&WT.tz=-4&WT.bh=9&WT.ul=en-US&WT.cd=24&WT.sr=1366x768&WT.jo=Yes&WT.ti=The%20New%20York%20Times%20-%20Breaking%20News,%20World%20News%20%26%20Multimedia&WT.js=Yes&WT.jv=1.7&WT.ct=unknown&WT.bs=994x649&WT.fi=No&WT.tv=1.0.7&WT.dl=0&WT.es=www.nytimes.com/&WT.z_fbc=&WT.cg_n=Homepage&WT.z_rcgn=Homepage&WT.z_gpt=Homepage&WT.z_nyts=&WT.z_nytd=&WT.z_rmid=007f010022166047bee9002b&WT.rv=0&WT.mc_ev=&WT.vt_f_tlh=0&WT.vt_f_d=1&WT.vt_f_s=1&WT.vt_f_a=1&WT.vt_f=1" + }, + { + "content-length": "0" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAABAAAAmLwAAIcelVCHHpVQAQAAAHhHAACHHpVQhx6VUAAAAAA-; path=/; expires=Thu, 10-Dec-2015 10:27:34 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:19 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAABAAAAmLwAAIcelVCHHpVQAQAAAHhHAACHHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:19 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Mon, 27 Aug 2012 21:22:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "430" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=45030" + }, + { + "expires": "Sun, 04 Nov 2012 02:09:49 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:19 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:27:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1103" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=82037" + }, + { + "expires": "Sun, 04 Nov 2012 12:26:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:19 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1766" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=45133" + }, + { + "expires": "Sun, 04 Nov 2012 02:11:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:19 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"15850e53f035443e5db6f28f75a9c1ac:1351623427\"" + }, + { + "last-modified": "Tue, 30 Oct 2012 18:57:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=1200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "content-length": "17391" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "public, max-age=600" + }, + { + "content-type": "text/javascript;charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:39:18 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:31:16 GMT" + }, + { + "server": "ECS (lhr/4BD8)" + }, + { + "status": "200 OK" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "9879" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:22 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 13:39:22 GMT" + }, + { + "last-modified": "Tue, 31 Jul 2012 23:02:57 GMT" + }, + { + "server": "ECS (lhr/4BF1)" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "35" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"f523ab9a498518867f12ca24f39ed087:1310577714\"" + }, + { + "last-modified": "Wed, 13 Jul 2011 17:10:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/gif" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "cache-control": "max-age=1200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:21 GMT" + }, + { + "content-length": "14202" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "text/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:39:24 GMT" + }, + { + "etag": "\"894881535586350a54ec0f6e94779ee35c2169bd\"" + }, + { + "x-age": "0" + }, + { + "x-cache": "MISS" + }, + { + "x-cache-hits": "0" + }, + { + "x-kuid": "IAJ5Qqdp" + }, + { + "x-request-backend": "user_data" + }, + { + "x-served-by": "apiservices-a002.krxd.net" + }, + { + "content-length": "100" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:24 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:24 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=250 t=1351949964465812" + }, + { + "x-served-by": "beacon-a002.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:25 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "public, max-age=604800" + }, + { + "content-type": "text/css;charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:39:21 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 10:41:53 GMT" + }, + { + "server": "ECS (lhr/4B9B)" + }, + { + "status": "200 OK" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "54615" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "131" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=63879" + }, + { + "expires": "Sun, 04 Nov 2012 07:24:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:28 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "130" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=41854" + }, + { + "expires": "Sun, 04 Nov 2012 01:17:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:28 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAABAAAAmLwAAJEelVCHHpVQAQAAAHhHAACRHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:29 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "303" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "content-type": "text/plain" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "0" + }, + { + "vary": "Host" + }, + { + "location": "http://www.nytimes.com/glogin?URI=http://www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html&OQ=hpQ26_rQ3D0&OP=36bee93bQ2FQ27NgQ3FQ27zwQ3FQ27nnnQ27vQ3FoJQ27!N)ujNNQ3FQ2FQ27Q2FQ60Q22Q2FQ27Q22Q22Q27Q60Q20Q27TuQ27gSzzuwJEQ24zCQ240NoCQ3FQ3FS!0gNCuNz0!Q24Q3FQ240Cz0nQ24Q3FSj0jSgNjQ3FQ3AvQ3FoJ" + } + ] + }, + { + "headers": [ + { + ":status": "302" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "content-type": "text/html" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "set-cookie": "NYT-S=0MdTeGr8L1EDLDXrmvxADeHzL3eTxUhvw7deFz9JchiAIUFL2BEX5FWcV.Ynx4rkFI; expires=Mon, 03-Dec-2012 13:39:29 GMT; path=/; domain=.nytimes.com" + }, + { + "location": "http://www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html?hp&_r=0" + }, + { + "content-length": "0" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html; charset=UTF-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "495" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=72064" + }, + { + "expires": "Sun, 04 Nov 2012 09:40:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "539" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=30984" + }, + { + "expires": "Sat, 03 Nov 2012 22:15:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "777" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=70943" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "172" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=55043" + }, + { + "expires": "Sun, 04 Nov 2012 04:56:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:27:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7026" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=67908" + }, + { + "expires": "Sun, 04 Nov 2012 08:31:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "content-type": "text/html" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "set-cookie": "NYT-S=0MdTeGr8L1EDLDXrmvxADeHzL3eTxUhvw7deFz9JchiAIUFL2BEX5FWcV.Ynx4rkFI; expires=Mon, 03-Dec-2012 13:39:29 GMT; path=/; domain=.nytimes.com" + }, + { + "location": "http://www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html?hp&_r=0" + }, + { + "content-length": "0" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MTlTX5YhqzXfDXrmvxADeHBiKThPzJplXdeFz9JchiAJK89nlVaR7bsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "vary": "Host" + }, + { + "cteonnt-length": "61027" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:27:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3093" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=71366" + }, + { + "expires": "Sun, 04 Nov 2012 09:28:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5636" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=71943" + }, + { + "expires": "Sun, 04 Nov 2012 09:38:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Mon, 15 Oct 2012 20:38:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "2481" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70868" + }, + { + "expires": "Sun, 04 Nov 2012 09:20:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 15 Oct 2012 20:38:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1241" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=67395" + }, + { + "expires": "Sun, 04 Nov 2012 08:22:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\"" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "x-aspnet-version": "2.0.50727" + }, + { + "content-length": "1" + }, + { + "cache-control": "private" + }, + { + "content-type": "text/plain; charset=utf-8" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:11:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "568" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=72065" + }, + { + "expires": "Sun, 04 Nov 2012 09:40:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1307" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=67397" + }, + { + "expires": "Sun, 04 Nov 2012 08:22:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:48:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "47727" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=66869" + }, + { + "expires": "Sun, 04 Nov 2012 08:13:58 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 17 Sep 2012 20:20:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2093" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70944" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "693" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=67422" + }, + { + "expires": "Sun, 04 Nov 2012 08:23:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2045" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71899" + }, + { + "expires": "Sun, 04 Nov 2012 09:37:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1052" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71981" + }, + { + "expires": "Sun, 04 Nov 2012 09:39:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:11:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2466" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=72115" + }, + { + "expires": "Sun, 04 Nov 2012 09:41:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "885" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70944" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 10 Sep 2012 21:02:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3686" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=67060" + }, + { + "expires": "Sun, 04 Nov 2012 08:17:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "636" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=72224" + }, + { + "expires": "Sun, 04 Nov 2012 09:43:13 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "850" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70987" + }, + { + "expires": "Sun, 04 Nov 2012 09:22:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1057" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70895" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:47:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1577" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70868" + }, + { + "expires": "Sun, 04 Nov 2012 09:20:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "546" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71763" + }, + { + "expires": "Sun, 04 Nov 2012 09:35:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MTlTX5YhqzXfDXrmvxADeHBiKThPzJplXdeFz9JchiAJK89nlVaR7bsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1911" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71744" + }, + { + "expires": "Sun, 04 Nov 2012 09:35:13 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "648" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=66989" + }, + { + "expires": "Sun, 04 Nov 2012 08:15:58 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MWfXncvqFxdbDXrmvxADeHBiKThPzJplXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cteonnt-length": "45" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "59" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "956" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=66847" + }, + { + "expires": "Sun, 04 Nov 2012 08:13:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "303" + }, + { + "cache-control": "private" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "location": "http://d1aivi5dp2wry5.cloudfront.net/pixel.gif" + }, + { + "p3p": "CP=\"NOI PSAo OUR IND COM NAV STA\"" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 25 Mar 2011 19:37:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1110" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=251474" + }, + { + "expires": "Tue, 06 Nov 2012 11:30:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "525" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70973" + }, + { + "expires": "Sun, 04 Nov 2012 09:22:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "522" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=66881" + }, + { + "expires": "Sun, 04 Nov 2012 08:14:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1766" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=63849" + }, + { + "expires": "Sun, 04 Nov 2012 07:23:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "864" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=72341" + }, + { + "expires": "Sun, 04 Nov 2012 09:45:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5039" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=66914" + }, + { + "expires": "Sun, 04 Nov 2012 08:14:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 11 Oct 2012 22:21:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "561" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70935" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 26 Apr 2012 15:13:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8381" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=351783" + }, + { + "expires": "Wed, 07 Nov 2012 15:22:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Thu, 04 Nov 2010 16:47:55 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1896" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=51812" + }, + { + "expires": "Sun, 04 Nov 2012 04:03:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 17 Sep 2012 18:13:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5551" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=71858" + }, + { + "expires": "Sun, 04 Nov 2012 09:37:07 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 01:19:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "15650" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=571282" + }, + { + "expires": "Sat, 10 Nov 2012 04:20:51 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 22:23:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "22905" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=51812" + }, + { + "expires": "Sun, 04 Nov 2012 04:03:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1713" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=70944" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 11 Sep 2009 17:35:00 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "69" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=72168" + }, + { + "expires": "Sun, 04 Nov 2012 09:42:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 30 May 2012 16:54:32 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "13402" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=18685" + }, + { + "expires": "Sat, 03 Nov 2012 18:50:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8728" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=67350" + }, + { + "expires": "Sun, 04 Nov 2012 08:21:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "656" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=67439" + }, + { + "expires": "Sun, 04 Nov 2012 08:23:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5248" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=70974" + }, + { + "expires": "Sun, 04 Nov 2012 09:22:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1103" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=70946" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "YvVdaXFdQYBoLiHhS/Pvn3QQnQ4PguJp3trhCHZSnIIo5NT7S98Tdyovty62vHSG" + }, + { + "x-amz-request-id": "CD0C61042E9125AE" + }, + { + "date": "Thu, 05 Jul 2012 20:17:51 GMT" + }, + { + "cache-control": "max-age=600000" + }, + { + "last-modified": "Wed, 28 Sep 2011 20:00:18 GMT" + }, + { + "etag": "\"df3e567d6f16d040326c7a0ea29a4f41\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "64616" + }, + { + "x-amz-cf-id": "oorNbpV0j8hpPM9RfynFxe0GrjwY7QWan8Mzs8SdZ-6uuC5_pgLgZA==" + }, + { + "via": "1.0 2cfcdac9b945cce88c21cc3f30d884cd.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "126" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=67490" + }, + { + "expires": "Sun, 04 Nov 2012 08:24:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=8F26281382200A491A2301632AB3A6B8&e=i.1354338000&t=i.10&v=i.1&l=l.25.2802408197.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.1.0.0.0&pr=l.4.2.0.0.0&vp=i.0&gf=l.10.2802408197.-1.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:29 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "113" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 16 Oct 2012 21:00:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5399" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=66914" + }, + { + "expires": "Sun, 04 Nov 2012 08:14:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1401" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=71732" + }, + { + "expires": "Sun, 04 Nov 2012 09:35:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 02 Mar 2011 21:46:12 GMT" + }, + { + "etag": "\"195-49d86d768f100\"" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-host": "b103 D=2883" + }, + { + "keep-alive": "timeout=120, max=990" + }, + { + "content-type": "application/javascript" + }, + { + "connection": "Keep-Alive" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "age": "93 " + }, + { + "content-length": "405" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3831" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=71853" + }, + { + "expires": "Sun, 04 Nov 2012 09:37:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:26:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1246" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70966" + }, + { + "expires": "Sun, 04 Nov 2012 09:22:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "37497" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=72227" + }, + { + "expires": "Sun, 04 Nov 2012 09:43:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9877" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=70946" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "424" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71023" + }, + { + "expires": "Sun, 04 Nov 2012 09:23:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "268" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=67682" + }, + { + "expires": "Sun, 04 Nov 2012 08:27:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "873" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=70936" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:11:33 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "368" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71023" + }, + { + "expires": "Sun, 04 Nov 2012 09:23:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3481" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=71854" + }, + { + "expires": "Sun, 04 Nov 2012 09:37:03 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "550" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70868" + }, + { + "expires": "Sun, 04 Nov 2012 09:20:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=51842" + }, + { + "expires": "Sun, 04 Nov 2012 04:03:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "content-length": "9458" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2328" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=51833" + }, + { + "expires": "Sun, 04 Nov 2012 04:03:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:27:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2619" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=51842" + }, + { + "expires": "Sun, 04 Nov 2012 04:03:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "129" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=51812" + }, + { + "expires": "Sun, 04 Nov 2012 04:03:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:27:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "35" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=42508" + }, + { + "expires": "Sun, 04 Nov 2012 01:27:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "68" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=69239" + }, + { + "expires": "Sun, 04 Nov 2012 08:53:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "46" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=71028" + }, + { + "expires": "Sun, 04 Nov 2012 09:23:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1147" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=66888" + }, + { + "expires": "Sun, 04 Nov 2012 08:14:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:29 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 01 Mar 2011 22:54:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2078" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=251463" + }, + { + "expires": "Tue, 06 Nov 2012 11:30:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 03 Mar 2011 19:32:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "593" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=251463" + }, + { + "expires": "Tue, 06 Nov 2012 11:30:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 03 Mar 2011 19:32:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1062" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=251463" + }, + { + "expires": "Tue, 06 Nov 2012 11:30:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 03 Mar 2011 19:32:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "830" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=251463" + }, + { + "expires": "Tue, 06 Nov 2012 11:30:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "46" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=65132" + }, + { + "expires": "Sun, 04 Nov 2012 07:45:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 03 Mar 2011 19:32:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "319" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=251463" + }, + { + "expires": "Tue, 06 Nov 2012 11:30:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 25 Mar 2011 19:37:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "68" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=1148040" + }, + { + "expires": "Fri, 16 Nov 2012 20:33:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "server": "Apache" + }, + { + "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;" + }, + { + "ntcoent-length": "89" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "99" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "156" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "server": "Apache" + }, + { + "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "522" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "5623" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 11 Oct 2012 22:51:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5799" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=351376" + }, + { + "expires": "Wed, 07 Nov 2012 15:15:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 10:59:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9147" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=336431" + }, + { + "expires": "Wed, 07 Nov 2012 11:06:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 17:13:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9389" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=445021" + }, + { + "expires": "Thu, 08 Nov 2012 17:16:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 11 Oct 2012 22:48:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5801" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=349648" + }, + { + "expires": "Wed, 07 Nov 2012 14:46:58 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Thu, 01 Nov 2012 04:10:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9726" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=402546" + }, + { + "expires": "Thu, 08 Nov 2012 05:28:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:47:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8968" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568247" + }, + { + "expires": "Sat, 10 Nov 2012 03:30:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "2160" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "384" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=66991" + }, + { + "expires": "Sun, 04 Nov 2012 08:16:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3710" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=71770" + }, + { + "expires": "Sun, 04 Nov 2012 09:35:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1435" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=72025" + }, + { + "expires": "Sun, 04 Nov 2012 09:39:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "193" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=66872" + }, + { + "expires": "Sun, 04 Nov 2012 08:14:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11292" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=67441" + }, + { + "expires": "Sun, 04 Nov 2012 08:23:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1968" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=70895" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:05 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:30 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "645" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=67389" + }, + { + "expires": "Sun, 04 Nov 2012 08:22:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6174" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=63855" + }, + { + "expires": "Sun, 04 Nov 2012 07:23:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Sun, 04 Nov 2012 13:39:30 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/x-javascript" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1008" + }, + { + "last-modified": "Thu, 05 Jul 2012 20:14:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=86400, private" + }, + { + "vary": "Accept-Encoding" + }, + { + "nncoection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "server": "Apache" + }, + { + "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "max-age=86400, private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "451" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sun, 04 Nov 2012 13:39:30 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "303" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "location": "/dcsypfq3j00000gsclwfljaeo_6i3w/dcs.gif?dcsredirect=112&dcstlh=0&dcstlv=0&dcsdat=1351949970618&dcssip=www.nytimes.com&dcsuri=/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html&dcsqry=%3Fhp%26_r=0&dcsref=http://www.nytimes.com/&WT.co_f=130.129.68.73-2680109824.30259656&WT.vt_sid=130.129.68.73-2680109824.30259656.1351949959620&WT.tz=-4&WT.bh=9&WT.ul=en-US&WT.cd=24&WT.sr=1366x768&WT.jo=Yes&WT.ti=Pennsylvania%20Omitted%20Poison%20Data%20in%20Water%20Report%20-%20NYTimes.com&WT.js=Yes&WT.jv=1.7&WT.ct=unknown&WT.bs=994x649&WT.fi=No&WT.tv=1.0.7&WT.dl=0&WT.es=www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html&WT.z_cad=1&WT.z_fbc=0&WT.cg_n=U.S.&WT.z_rcgn=U.S.&WT.z_gpt=Article&WT.z_gpst=News&WT.cre=The%20New%20York%20Times&WT.z_nyts=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI&WT.z_nytd=&WT.z_rmid=007f010022166047bee9002b&WT.z_ref=nytimes.com&WT.rv=0&WT.z_hdl=Pennsylvania%20Omitted%20Poison%20Data%20in%20Water%20Report&WT.z_aid=nyta-100000001882561&WT.z_pud=20121102&WT.z_put=Archive&WT.z.gsg=Archive&WT.z_gat=1987-Present&WT.z_pua=free&WT.z_clmst=JON%20HURDLE&WT.z_puv=Normal&WT.z_pudr=1%20Day&WT.z_pyr=2012&WT.mc_ev=&WT.vt_f_tlv=&WT.vt_f_tlh=1351949969&WT.vt_f_d=&WT.vt_f_s=&WT.vt_f_a=&WT.vt_f=" + }, + { + "content-length": "0" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAACAAAAmLwAAJEelVCHHpVQ9r0AAJIelVCSHpVQAQAAAHhHAACSHpVQhx6VUAAAAAA-; path=/; expires=Thu, 10-Dec-2015 10:27:34 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs3719rcF5/JLq6ryuLbPLJXeyC9jZZv+I7SU4qR++R9DDoNb/ysNCSXuwJ979WKhzt9zeOAxNfu6nTWtMntzlCge0zMN6tn5CjIsSTK5oUfaLnJaYMq4VYwS5vxNRs6EHC1nNdLw29SQ2GQ1OzYMBqy0e3FBBr8pVvZLpT4SSw1y6vIpitypkpC3SUacb3M5M=; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:30 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas09-2" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Sun, 04 Nov 2012 13:39:30 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/css" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "684" + }, + { + "last-modified": "Thu, 05 Jul 2012 19:11:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=86400, private" + }, + { + "vary": "Accept-Encoding" + }, + { + "nncoection": "close" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAACAAAAmLwAAJEelVCHHpVQ9r0AAJIelVCSHpVQAQAAAHhHAACSHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:30 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 27 Aug 2012 21:22:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "430" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=67493" + }, + { + "expires": "Sun, 04 Nov 2012 08:24:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 14 Mar 2012 16:16:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2791" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=547136" + }, + { + "expires": "Fri, 09 Nov 2012 21:38:26 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 22 Oct 2012 21:27:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1103" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=43733" + }, + { + "expires": "Sun, 04 Nov 2012 01:48:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1330" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=72392" + }, + { + "expires": "Sun, 04 Nov 2012 09:46:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1261" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=72392" + }, + { + "expires": "Sun, 04 Nov 2012 09:46:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1687" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=67920" + }, + { + "expires": "Sun, 04 Nov 2012 08:31:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "74" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=67981" + }, + { + "expires": "Sun, 04 Nov 2012 08:32:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 17 Jul 2012 16:21:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1029" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=72522" + }, + { + "expires": "Sun, 04 Nov 2012 09:48:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 17 Jul 2012 16:21:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "108" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=70940" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:50 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "73" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=67925" + }, + { + "expires": "Sun, 04 Nov 2012 08:31:35 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "server": "Apache" + }, + { + "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "max-age=604800, private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1211" + }, + { + "last-modified": "Wed, 14 Mar 2012 16:16:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 10 Nov 2012 13:39:30 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/css" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "684" + }, + { + "last-modified": "Thu, 05 Jul 2012 19:11:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=86400, private" + }, + { + "vary": "Accept-Encoding" + }, + { + "nncoection": "close" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 12 Oct 2012 20:42:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10779" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=66917" + }, + { + "expires": "Sun, 04 Nov 2012 08:14:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 12:45:53 GMT" + }, + { + "server": "safe" + }, + { + "cache-control": "public, max-age=3600" + }, + { + "content-length": "141" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-type": "application/ocsp-response" + }, + { + "content-length": "1330" + }, + { + "date": "Sat, 03 Nov 2012 13:39:30 GMT" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT" + }, + { + "x-content-type-options": "nosniff" + }, + { + "x-fb-debug": "viBL2OtZRmc+1Eqe26sXit4heGPBgfLwrdCHHhHx73Y=" + }, + { + "content-length": "1916" + }, + { + "cache-control": "public, max-age=25750987" + }, + { + "expires": "Wed, 28 Aug 2013 14:42:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:31 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:31 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:31 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=263 t=1351949971765301" + }, + { + "x-served-by": "beacon-a006.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=1800" + }, + { + "content-type": "text/javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:39:31 GMT" + }, + { + "etag": "\"ad69b1e55307637e8f511c3651fe4a796330656f\"" + }, + { + "x-age": "0" + }, + { + "x-cache": "MISS" + }, + { + "x-cache-hits": "0" + }, + { + "x-kuid": "IAJ5QtWI" + }, + { + "x-request-backend": "user_data" + }, + { + "x-served-by": "apiservices-a002.krxd.net" + }, + { + "content-length": "117" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:31 GMT" + }, + { + "content-type": "image/x-icon" + }, + { + "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/css" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "684" + }, + { + "last-modified": "Thu, 05 Jul 2012 19:11:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=86400, private" + }, + { + "vary": "Accept-Encoding" + }, + { + "nncoection": "close" + }, + { + "cneonction": "close" + }, + { + "content-length": "1406" + }, + { + "last-modified": "Fri, 03 Aug 2012 23:51:15 GMT" + }, + { + "etag": "\"57e-501c63f3\"" + }, + { + "accept-ranges": "bytes" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 11:36:59 GMT" + }, + { + "etag": "\"30-4cd95ab8fecc0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-host": "b205 D=2031" + }, + { + "keep-alive": "timeout=120, max=972" + }, + { + "content-type": "application/javascript" + }, + { + "connection": "Keep-Alive" + }, + { + "date": "Sat, 03 Nov 2012 13:39:31 GMT" + }, + { + "age": "161 " + }, + { + "content-length": "48" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:30:44 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5873" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=419" + }, + { + "expires": "Sat, 03 Nov 2012 13:46:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:31 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 15 Jul 2010 17:33:38 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "583" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=251500" + }, + { + "expires": "Tue, 06 Nov 2012 11:31:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 25 Oct 2007 19:58:55 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "79" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=251499" + }, + { + "expires": "Tue, 06 Nov 2012 11:31:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:32 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "etag": "\"d04742eb975012ec5e5aecce3effd7ce:1350417145\"" + }, + { + "last-modified": "Tue, 25 Sep 2012 18:41:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "application/x-javascript" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:31 GMT" + }, + { + "content-length": "3167" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.7.67" + }, + { + "date": "Sat, 03 Nov 2012 13:39:32 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "235" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=50212" + }, + { + "expires": "Sun, 04 Nov 2012 03:36:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:12:26 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "402" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70900" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:20 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1108" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=45394" + }, + { + "expires": "Sun, 04 Nov 2012 02:16:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "content-type": "image/x-icon" + }, + { + "set-cookie": "NYT-S=0MuwkWjSilDpbDXrmvxADeHGJBFC9b9qDRdeFz9JchiAKuaKkdl/6loIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "684" + }, + { + "last-modified": "Thu, 05 Jul 2012 19:11:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=86400, private" + }, + { + "vary": "Host" + }, + { + "nncoection": "close" + }, + { + "cneonction": "close" + }, + { + "content-length": "1406" + }, + { + "last-modified": "Fri, 03 Aug 2012 23:51:15 GMT" + }, + { + "etag": "\"57e-501c63f3\"" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "ntcoent-length": "142315" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:20:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2017" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64909" + }, + { + "expires": "Sun, 04 Nov 2012 07:41:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 05 Jul 2012 21:20:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1687" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=43" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 13:51:54 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9372" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=519781" + }, + { + "expires": "Fri, 09 Nov 2012 14:02:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Thu, 01 Nov 2012 18:59:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "21158" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=451415" + }, + { + "expires": "Thu, 08 Nov 2012 19:03:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 02:58:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9420" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=480982" + }, + { + "expires": "Fri, 09 Nov 2012 03:16:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 24 May 2012 19:30:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1217" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=31" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:11 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 17 May 2012 20:43:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "586" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=57" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 05 Jul 2012 21:20:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "17724" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=44" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "586" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=70933" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:24 GMT" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "max-age=604800, private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1211" + }, + { + "last-modified": "Wed, 14 Mar 2012 16:16:16 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MlRvbBBJvPrbDXrmvxADeHGBFC0o.wGyedeFz9JchiAKuaKkdl/6loIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "593" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=72068" + }, + { + "expires": "Sun, 04 Nov 2012 09:40:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "380" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=76028" + }, + { + "expires": "Sun, 04 Nov 2012 10:46:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1435" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=67567" + }, + { + "expires": "Sun, 04 Nov 2012 08:25:47 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 10:03:09 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6703" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568282" + }, + { + "expires": "Sat, 10 Nov 2012 03:31:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 15:35:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10892" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 27 Oct 2012 00:21:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9029" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 29 Oct 2012 16:05:06 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10524" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568298" + }, + { + "expires": "Sat, 10 Nov 2012 03:31:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2045" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71054" + }, + { + "expires": "Sun, 04 Nov 2012 09:23:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "416" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71053" + }, + { + "expires": "Sun, 04 Nov 2012 09:23:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 29 Oct 2012 19:05:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "31084" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "402" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=71054" + }, + { + "expires": "Sun, 04 Nov 2012 09:23:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 20 May 2011 16:30:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9829" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:14:44 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "526" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=50213" + }, + { + "expires": "Sun, 04 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 14:49:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "67" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=217288" + }, + { + "expires": "Tue, 06 Nov 2012 02:01:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 21 Apr 2010 19:31:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "507" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=307895" + }, + { + "expires": "Wed, 07 Nov 2012 03:11:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 21 Apr 2010 19:31:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1578" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=358516" + }, + { + "expires": "Wed, 07 Nov 2012 17:14:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 03 Mar 2010 22:58:31 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1927" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=601439" + }, + { + "expires": "Sat, 10 Nov 2012 12:43:39 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Mon, 29 Oct 2012 19:39:26 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "10726" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568482" + }, + { + "expires": "Sat, 10 Nov 2012 03:34:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 23 Oct 2012 05:20:00 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9316" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 28 Dec 2006 14:20:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "183" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=349196" + }, + { + "expires": "Wed, 07 Nov 2012 14:39:36 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 29 Oct 2012 04:24:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "13748" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 10:40:02 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8817" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Fri, 14 Mar 2008 23:03:40 GMT" + }, + { + "etag": "\"19f-4486dae50ab00\"" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-host": "b203 D=1778" + }, + { + "keep-alive": "timeout=120, max=997" + }, + { + "content-type": "application/javascript" + }, + { + "connection": "Keep-Alive" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "age": "43 " + }, + { + "content-length": "415" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=65755B60FD3DAC5F62160A7CED54655D&e=i.1354338000&t=i.10&v=i.1&l=l.25.2802408197.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.1.0.0.0&pr=l.4.3.0.0.0&vp=i.0&gf=l.10.2802408197.-1.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:40 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "114" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 29 Oct 2012 19:28:25 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8578" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 29 Oct 2012 18:53:28 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "40163" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Oct 2012 00:59:01 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "31146" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=582958" + }, + { + "expires": "Sat, 10 Nov 2012 07:35:38 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Mon, 22 Oct 2012 17:24:54 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "16403" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Oct 2012 18:43:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11670" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=308055" + }, + { + "expires": "Wed, 07 Nov 2012 03:13:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 28 Apr 2010 14:36:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "987" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=568614" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 28 Apr 2010 14:36:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2533" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=568614" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 19 Sep 2012 16:22:54 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "14479" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568614" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 09 Apr 2012 21:40:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "14215" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568614" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Thu, 11 Dec 2008 21:32:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "2981" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=568614" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 17:09:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "13040" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=43242" + }, + { + "expires": "Sun, 04 Nov 2012 01:40:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 28 Apr 2009 18:18:22 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "441" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=43242" + }, + { + "expires": "Sun, 04 Nov 2012 01:40:22 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 21:41:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "14372" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=54908" + }, + { + "expires": "Sun, 04 Nov 2012 04:54:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 01 Apr 2009 23:28:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1305" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=30976" + }, + { + "expires": "Sat, 03 Nov 2012 22:15:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 20 Mar 2012 16:46:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "16641" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=76250" + }, + { + "expires": "Sun, 04 Nov 2012 10:50:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "public, max-age=600" + }, + { + "content-type": "text/javascript;charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:39:40 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:32:42 GMT" + }, + { + "server": "ECS (lhr/4BB6)" + }, + { + "status": "200 OK" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "9160" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "64" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=70518" + }, + { + "expires": "Sun, 04 Nov 2012 09:14:59 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:15:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2092" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private, max-age=86400" + }, + { + "expires": "Sun, 04 Nov 2012 13:39:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 23 Sep 2011 19:12:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1453" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=47" + }, + { + "expires": "Sat, 03 Nov 2012 13:40:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "119" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=65032" + }, + { + "expires": "Sun, 04 Nov 2012 07:43:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1261" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=65032" + }, + { + "expires": "Sun, 04 Nov 2012 07:43:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "188" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=70571" + }, + { + "expires": "Sun, 04 Nov 2012 09:15:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:14:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "74" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=70936" + }, + { + "expires": "Sun, 04 Nov 2012 09:21:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 28 Aug 2012 21:17:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "880" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64971" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4164" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=76141" + }, + { + "expires": "Sun, 04 Nov 2012 10:48:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "230" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64971" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2404" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64971" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "5136" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64867" + }, + { + "expires": "Sun, 04 Nov 2012 07:40:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "29137" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64954" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5752" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64971" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "723" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=76141" + }, + { + "expires": "Sun, 04 Nov 2012 10:48:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "server": "Apache" + }, + { + "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "586" + }, + { + "last-modified": "Thu, 06 Dec 2007 12:15:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "vary": "Host" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MlRvbBBJvPrbDXrmvxADeHGBFC0o.wGyedeFz9JchiAKuaKkdl/6loIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "transfer-encoding": "chunked" + }, + { + "etag": "\"14f8931-69a-4409d16c699c0\"" + }, + { + "cteonnt-length": "1690" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 14:50:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "170" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=348768" + }, + { + "expires": "Wed, 07 Nov 2012 14:32:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 May 2010 14:50:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "106" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=348768" + }, + { + "expires": "Wed, 07 Nov 2012 14:32:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 14 May 2010 14:50:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "3113" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=348768" + }, + { + "expires": "Wed, 07 Nov 2012 14:32:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2303" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=64971" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "16036" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64972" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 31 Aug 2010 02:21:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "783" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=64970" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 17 Jan 2011 01:28:46 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1930" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=86400" + }, + { + "expires": "Sun, 04 Nov 2012 13:39:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 24 Jun 2009 19:31:51 GMT" + }, + { + "etag": "\"1506ccd-181-46d1d28b0d7c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cteonnt-length": "385" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "233" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1875" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1313" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64974" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:35 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "956" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=65049" + }, + { + "expires": "Sun, 04 Nov 2012 07:43:50 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 24 Apr 2012 15:30:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7711" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 23 Jun 2011 19:37:35 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8232" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Tue, 28 Feb 2012 20:00:47 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "8082" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 23 Jun 2011 20:05:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8047" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 16 Mar 2012 15:04:36 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8295" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs37yNvMF5jo9YXjSnP7LCTHV9qwwoXglYNnSgoXY6BgbxUe/dD4KFNMYHqMNEyxe2rbNMTaq4ZLc54Mwg8CSJxvNnh/ajkRBOJfEPCwjrLmcL1OEvcVlVd6ZL/LHB0ixoNHfgWDborMHCUfZtXPvcBFlRNv7qTCM+wn7NY4LUipF+V+epFmBpnIArrjDPO; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:41 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas12-2" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 21:16:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8374" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "303" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "location": "/dcsaon9rw0000008ifmgqtaeo_2f9c/dcs.gif?dcsredirect=112&dcstlh=0&dcstlv=0&dcsdat=1351949981735&dcssip=www.nytimes.com&dcsuri=/pages/science/index.html&dcsref=http://www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html%3Fhp%26_r=0&WT.co_f=130.129.68.73-2680109824.30259656&WT.vt_sid=130.129.68.73-2680109824.30259656.1351949959620&WT.tz=-4&WT.bh=9&WT.ul=en-US&WT.cd=24&WT.sr=1366x768&WT.jo=Yes&WT.ti=Science%20News%20-%20The%20New%20York%20Times&WT.js=Yes&WT.jv=1.7&WT.ct=unknown&WT.bs=994x649&WT.fi=No&WT.tv=1.0.7&WT.dl=0&WT.es=www.nytimes.com/pages/science/index.html&WT.cg_n=Science&WT.z_rcgn=Science&WT.z_gpt=Section%20Front&WT.z_nyts=0MlRvbBBJvPrbDXrmvxADeHGBFC0o.wGyedeFz9JchiAKuaKkdl/6loIV.Ynx4rkFI&WT.z_nytd=&WT.z_rmid=007f010022166047bee9002b&WT.z_ref=nytimes.com&WT.rv=0&WT.mc_ev=&WT.vt_f_tlv=&WT.vt_f_tlh=1351949981&WT.vt_f_d=&WT.vt_f_s=&WT.vt_f_a=&WT.vt_f=" + }, + { + "content-length": "0" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAADAAAAmLwAAJEelVCHHpVQ9r0AAJIelVCSHpVQ+r0AAJ0elVCdHpVQAQAAAHhHAACdHpVQhx6VUAAAAAA-; path=/; expires=Thu, 10-Dec-2015 10:27:34 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 08 Sep 2011 15:52:38 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8274" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 21:21:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8001" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Mon, 04 Apr 2011 17:44:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "8310" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568612" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 13 Mar 2012 15:48:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8162" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 19:24:18 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8410" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 19:26:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8253" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 30 Mar 2011 20:20:51 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8372" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 19:25:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8030" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 24 Jun 2009 19:31:51 GMT" + }, + { + "etag": "\"1506ccd-181-46d1d28b0d7c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cteonnt-length": "385" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "74" + }, + { + "ntcoent-length": "62" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 09 Mar 2012 18:41:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "8093" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 21:31:02 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8036" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 14 Mar 2012 19:42:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8124" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 21:33:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8207" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 21:36:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8363" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 29 Mar 2011 21:41:44 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8151" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568613" + }, + { + "expires": "Sat, 10 Nov 2012 03:36:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAADAAAAmLwAAJEelVCHHpVQ9r0AAJIelVCSHpVQ+r0AAJ0elVCdHpVQAQAAAHhHAACdHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:41 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 17 Mar 2010 16:56:32 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "20" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private, max-age=64931" + }, + { + "expires": "Sun, 04 Nov 2012 07:41:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 13:39:41 GMT" + }, + { + "last-modified": "Tue, 31 Jul 2012 23:02:57 GMT" + }, + { + "server": "ECS (lhr/4BF1)" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "35" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "content-encoding": "gzip" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "public, max-age=604800" + }, + { + "content-type": "text/css;charset=utf-8" + }, + { + "date": "Sat, 03 Nov 2012 13:39:41 GMT" + }, + { + "last-modified": "Sun, 28 Oct 2012 04:22:00 GMT" + }, + { + "server": "ECS (lhr/4BB5)" + }, + { + "status": "200 OK" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "136727" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:43 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:43 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=245 t=1351949983602996" + }, + { + "x-served-by": "beacon-a006.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.7.67" + }, + { + "date": "Sat, 03 Nov 2012 13:39:43 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 21 Aug 2012 20:06:02 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1780" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=72048" + }, + { + "expires": "Sun, 04 Nov 2012 09:40:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "511" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=72077" + }, + { + "expires": "Sun, 04 Nov 2012 09:41:02 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Tue, 30 Oct 2012 16:29:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "6000" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=571763" + }, + { + "expires": "Sat, 10 Nov 2012 04:29:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 30 Oct 2012 16:26:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "6454" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=571763" + }, + { + "expires": "Sat, 10 Nov 2012 04:29:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "156" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0Ma.K9EWB.dlLDXrmvxADeHD./oTk5S0O8deFz9JchiAImJkOx2rgxzsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "vary": "Host" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "ntcoent-length": "64765" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 30 Oct 2012 17:02:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8653" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=571763" + }, + { + "expires": "Sat, 10 Nov 2012 04:29:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:54:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "21379" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=71749" + }, + { + "expires": "Sun, 04 Nov 2012 09:35:34 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 14:47:21 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "15456" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=571763" + }, + { + "expires": "Sat, 10 Nov 2012 04:29:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 14:29:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "49747" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=571763" + }, + { + "expires": "Sat, 10 Nov 2012 04:29:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 12 Oct 2012 20:15:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3168" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=72146" + }, + { + "expires": "Sun, 04 Nov 2012 09:42:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 14 Jun 2012 20:14:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10547" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=49875" + }, + { + "expires": "Sun, 04 Nov 2012 03:31:01 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "303" + }, + { + "cache-control": "private" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + }, + { + "location": "http://d1aivi5dp2wry5.cloudfront.net/pixel.gif" + }, + { + "p3p": "CP=\"NOI PSAo OUR IND COM NAV STA\"" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=39895E64FA29A782E08DBEA5DC0005A0&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.4.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:46 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "113" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MKyyIqtYtFvnDXrmvxADeHJm9OXN6YxpedeFz9JchiAIrvq48TSAR4YV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "ntcoent-length": "50" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MKyyIqtYtFvnDXrmvxADeHJm9OXN6YxpedeFz9JchiAIrvq48TSAR4YV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cteonnt-length": "45" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "59" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + }, + { + "x-amz-id-2": "YvVdaXFdQYBoLiHhS/Pvn3QQnQ4PguJp3trhCHZSnIIo5NT7S98Tdyovty62vHSG" + }, + { + "x-amz-request-id": "CD0C61042E9125AE" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "cache-control": "max-age=600000" + }, + { + "last-modified": "Wed, 28 Sep 2011 20:00:18 GMT" + }, + { + "etag": "\"df3e567d6f16d040326c7a0ea29a4f41\"" + }, + { + "accept-ranges": "bytes" + }, + { + "server": "AmazonS3" + }, + { + "age": "64633" + }, + { + "x-amz-cf-id": "kbjTp1EH_MixUnZ7pqHXKi1pQZ7tCItHqSP2iVMrIwMt36MEvhC5bQ==" + }, + { + "via": "1.0 2cfcdac9b945cce88c21cc3f30d884cd.cloudfront.net (CloudFront)" + }, + { + "x-cache": "Hit from cloudfront" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "993" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MKyyIqtYtFvnDXrmvxADeHJm9OXN6YxpedeFz9JchiAIrvq48TSAR4YV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "vary": "Host" + }, + { + "cteonnt-length": "1220" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "767" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "156" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "Apache" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "522" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "59" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MrbR7PgLIdPLDXrmvxADeHJm9OXN6YxpedeFz9JchiAIa2oeaXI7u7sV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cteonnt-length": "45" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/json" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5623" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1071" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:46 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:39:45 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs3MVVvMC5/TPbCQtB9rewZ4ac3sWtlL/To9pTTnVflQ7/pHvfl9TutghgWq8BWX5hkGMxwV0G2TYPnu7UrqddmXeJqDHsu7UtpznAhQDBIXp76SiJpTi8Xt/SyOHvyVjspIxogIORYGOkXT50L77u7Afv+N5dTX/mGL4zVQJ5xgVd7PhAxSnfU7wMqMA10uXsSVCgB; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:46 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas14-2" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "67" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=75225" + }, + { + "expires": "Sun, 04 Nov 2012 10:33:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAADAAAAmLwAAJEelVCHHpVQ9r0AAKIelVCSHpVQ+r0AAJ0elVCdHpVQAQAAAHhHAACiHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:46 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:46 GMT" + }, + { + "server": "Apache" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "421" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MCYDgCh5sLPnDXrmvxADeHJm9OXN6YxpedeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cteonnt-length": "611" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "216" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "677" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1270" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=65537" + }, + { + "expires": "Sun, 04 Nov 2012 07:52:04 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 01 Oct 2012 22:20:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "850" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=82550" + }, + { + "expires": "Sun, 04 Nov 2012 12:35:37 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 25 Oct 2007 19:58:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "78" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=343858" + }, + { + "expires": "Wed, 07 Nov 2012 13:10:45 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 25 Jun 2012 18:51:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "193" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=348897" + }, + { + "expires": "Wed, 07 Nov 2012 14:34:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:47 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=261 t=1351949987674149" + }, + { + "x-served-by": "beacon-a002.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.7.67" + }, + { + "date": "Sat, 03 Nov 2012 13:39:47 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 25 Jun 2012 18:51:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "195" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=348898" + }, + { + "expires": "Wed, 07 Nov 2012 14:34:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:48 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:48 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 17 Nov 2011 21:55:54 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1439" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=348897" + }, + { + "expires": "Wed, 07 Nov 2012 14:34:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 27 Sep 2011 18:42:47 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "120" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=348920" + }, + { + "expires": "Wed, 07 Nov 2012 14:35:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 17 Nov 2010 22:08:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "79" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=348893" + }, + { + "expires": "Wed, 07 Nov 2012 14:34:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 17 Nov 2010 22:08:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "444" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=348893" + }, + { + "expires": "Wed, 07 Nov 2012 14:34:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "314" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=69564" + }, + { + "expires": "Sun, 04 Nov 2012 08:59:13 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:49 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "x-amz-id-2": "ceFRS1NFRp8F1PuWGjAzR4CMD8nHMNrIGG1K803RtQWtRwA6ZZIyFDi3hvyD0rEU" + }, + { + "x-amz-request-id": "1F4B6B1CFD329F7B" + }, + { + "date": "Sat, 03 Nov 2012 13:39:50 GMT" + }, + { + "last-modified": "Mon, 20 Aug 2012 08:07:13 GMT" + }, + { + "etag": "\"327b3e51a98ec9a7794030292d94bfdd\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "image/jpeg" + }, + { + "content-length": "2329" + }, + { + "server": "AmazonS3" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 11 Nov 2011 21:24:38 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "992" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=348902" + }, + { + "expires": "Wed, 07 Nov 2012 14:34:52 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:50 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:52 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MPfF5c8nIM93DXrmvxADeHz.PZL72gaixdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 12 Oct 2012 20:18:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4913" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=75470" + }, + { + "expires": "Sun, 04 Nov 2012 10:37:42 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:52 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 25 Oct 2012 15:40:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9921" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=62694" + }, + { + "expires": "Sun, 04 Nov 2012 07:04:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:52 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:52 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:52 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "59" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MVMayrSvblfnDXrmvxADeHz.PZL72gaixdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "45" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:38:56 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "216" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MrRmN0I2VxMLDXrmvxADeHx2AlW/TY.ZkdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:39:52 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=484D5CE2EC7396EB483BD34967CEFAEA&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.5.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:52 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "113" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1064" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html" + }, + { + "last-modified": "Thu, 12 Apr 2012 20:48:26 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "cache-control": "public, max-age=0" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "175" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "216" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M3MAhi1As7rzDXrmvxADeHIS37KQvQCBqdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "522" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M3MAhi1As7rzDXrmvxADeHIS37KQvQCBqdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MsUPd65dnaE7DXrmvxADeHIS37KQvQCBqdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cteonnt-length": "45" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "59" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "156" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html" + }, + { + "last-modified": "Mon, 27 Aug 2012 09:47:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "cache-control": "public, max-age=0" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "846" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "5623" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M3MAhi1As7rzDXrmvxADeHIS37KQvQCBqdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:53 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1015" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs38VNrMF5/o7ZYjynLbLK61Fp4LCE4qYA8/Pkh6qaTfl607NSARhRSu/Fzrhux2ZemT7dtNzdkLuaRJQuxoxMjsTLW4MWkvPvMQEm63fgskbXcOyhmIGhAp8smwaMCPqeCAzEoxoL8g46HoNIA8DP6t0XbPL6ADv/liREWAhRB2zl4cdzIiQpdChU6FSzIgUundpLxZgo=; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:53 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas07-3" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "5623" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MsUPd65dnaE7DXrmvxADeHIS37KQvQCBqdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "216" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MsUPd65dnaE7DXrmvxADeHIS37KQvQCBqdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:53 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "674" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:54 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:54 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=261 t=1351949994087668" + }, + { + "x-served-by": "beacon-a006.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.7.67" + }, + { + "date": "Sat, 03 Nov 2012 13:39:54 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:55 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MsUPd65dnaE7DXrmvxADeHIS37KQvQCBqdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 19 Sep 2012 14:55:07 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9556" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=18600" + }, + { + "expires": "Sat, 03 Nov 2012 18:49:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=BB78456D636A55DD29717BF2DF3A713D&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.6.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:57 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "113" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "674" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1086" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "522" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "156" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "5623" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "982" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html" + }, + { + "last-modified": "Thu, 12 Apr 2012 20:48:26 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "cache-control": "public, max-age=0" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "175" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs38VVrcF5/ZLq6rynLbPIrDNNqLmAVAjAcmlywO48hlDb+EIf12DpSuoFj6R+qKjtBkmg2hwh475ZyhKkLcXnOHD8snyDB8tqBczw0L+1ELClDEhhnAWZEtcBDLaM8gpIzDffofr8PXgb4mdcdsGQEwxlXd7J5w1a+LaHURhUo7KSjHyswVRH8QuXMXjpbXabRMAqNp3YYzXPS12ub; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:57 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas11-2" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "421" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MQAEyqJ3kflHDXrmvxADeHFvzcPY0HhncdeFz9JchiAIul1FwAbE3OsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "611" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:57 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:58 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "674" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:58 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "216" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "content-type": "text/html" + }, + { + "last-modified": "Mon, 27 Aug 2012 09:47:24 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "expires": "Sat, 03 Nov 2012 13:39:57 GMT" + }, + { + "cache-control": "public, max-age=0" + }, + { + "x-content-type-options": "nosniff" + }, + { + "server": "sffe" + }, + { + "content-length": "846" + }, + { + "x-xss-protection": "1; mode=block" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:39:58 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:39:58 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:58 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=258 t=1351949998446073" + }, + { + "x-served-by": "beacon-a006.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.7.67" + }, + { + "date": "Sat, 03 Nov 2012 13:39:58 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:40:00 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "1625" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "vary": "Host" + }, + { + "ntcoent-length": "59049" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "59" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MMbUZRWJFzCHDXrmvxADeHKjc4hKLrMXGdeFz9JchiALVSSvxGfo9IYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cteonnt-length": "45" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=A04BB1C6D05156CDD246EFA62A7CC3A3&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.7.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:40:03 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "113" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1065" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "vary": "Host" + }, + { + "cteonnt-length": "1240" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + }, + { + "content-length": "777" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "server": "Apache" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "522" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "156" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1013" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/json" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5623" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs37lNrMF5/o7ZYjynLbLK6rQEBceRsik1IRXIEfZYJjiQapJzwsXeZjT0U5HMKHV3mXKvvaQ4FLg4p3hY87Lr+QiD9QLBuC5Vhn49p+QQ/emsZO26pJ7Jdh6OeXLf4hds9p5K2fB19Ja95VikymGQrDgRB3gOb5zehMs2tUQJAktvEjgSgsPeIBsEg8ddP/NbMOovVC1aBKj+1; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:40:03 GMT; Path=/" + }, + { + "x-proc-data": "pd3-bgas14-2" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:40:03 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:03 GMT" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/json" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5623" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:40:04 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "674" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:40:04 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "216" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:04 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/json" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1628" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:40:04 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:40:04 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=274 t=1351950004445628" + }, + { + "x-served-by": "beacon-a006.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.7.67" + }, + { + "date": "Sat, 03 Nov 2012 13:40:04 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 23:48:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3699" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=79" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:23 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:04 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:05 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/json" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1628" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:14 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1397" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=55146" + }, + { + "expires": "Sun, 04 Nov 2012 04:59:15 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "server": "Apache" + }, + { + "ntcoent-length": "135910" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1628" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MZmF2WzRIAizDXrmvxADeHI4U72bYMorSdeFz9JchiALVSSvxGfo9IYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "transfer-encoding": "chunked" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "vary": "Host" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 17 Sep 2012 20:00:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1566" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=202" + }, + { + "expires": "Sat, 03 Nov 2012 13:43:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:21:37 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "9333" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=564467" + }, + { + "expires": "Sat, 10 Nov 2012 02:27:56 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 17:00:35 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8948" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=530746" + }, + { + "expires": "Fri, 09 Nov 2012 17:05:55 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1276" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=64897" + }, + { + "expires": "Sun, 04 Nov 2012 07:41:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 17 Sep 2012 20:00:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "19737" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=202" + }, + { + "expires": "Sat, 03 Nov 2012 13:43:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "248" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64919" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "921" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=20124" + }, + { + "expires": "Sat, 03 Nov 2012 19:15:33 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:10:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10427" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=571269" + }, + { + "expires": "Sat, 10 Nov 2012 04:21:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "59" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0Ma.K9EWB.dlLDXrmvxADeHI4U72bYMorSdeFz9JchiALJvjis/thrUYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cteonnt-length": "45" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:54:41 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "33089" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573548" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:13:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "8950" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=559591" + }, + { + "expires": "Sat, 10 Nov 2012 01:06:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "431" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/css" + }, + { + "cache-control": "private, max-age=64941" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:30 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Mar 2012 17:13:24 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "52128" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=97" + }, + { + "expires": "Sat, 03 Nov 2012 13:41:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 06:54:58 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10027" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=580777" + }, + { + "expires": "Sat, 10 Nov 2012 06:59:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 03:35:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9303" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573129" + }, + { + "expires": "Sat, 10 Nov 2012 04:52:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 00:50:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10045" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=559835" + }, + { + "expires": "Sat, 10 Nov 2012 01:10:44 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Fri, 02 Nov 2012 23:02:10 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "10110" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=552339" + }, + { + "expires": "Fri, 09 Nov 2012 23:05:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:40:24 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9118" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=568308" + }, + { + "expires": "Sat, 10 Nov 2012 03:31:57 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 02 Oct 2007 16:06:30 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "3308" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=573548" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 22:25:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "14634" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573549" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:22:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "14341" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573549" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:50:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "16624" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=361320" + }, + { + "expires": "Wed, 07 Nov 2012 18:02:09 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=918B6703052398FA5C152AAC782FA51F&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.8.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:40:09 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "114" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 30 Oct 2012 22:51:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "15006" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573549" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 20:07:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "51622" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=369068" + }, + { + "expires": "Wed, 07 Nov 2012 20:11:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Thu, 01 Nov 2012 02:55:22 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "19143" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=394445" + }, + { + "expires": "Thu, 08 Nov 2012 03:14:14 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 23:23:53 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "9474" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=553714" + }, + { + "expires": "Fri, 09 Nov 2012 23:28:43 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:48:38 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8030" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573439" + }, + { + "expires": "Sat, 10 Nov 2012 04:57:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 20 Jun 2012 14:59:39 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "10115" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573549" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 20 Aug 2009 21:16:01 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2105" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=351563" + }, + { + "expires": "Wed, 07 Nov 2012 15:19:32 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 04:00:27 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "35977" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573549" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Tue, 27 Apr 2010 17:46:57 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "1787" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=349039" + }, + { + "expires": "Wed, 07 Nov 2012 14:37:28 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 14 Oct 2011 20:04:24 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "8189" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573550" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 17 Jun 2011 13:57:26 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2824" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573550" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 15 Nov 2011 19:33:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11967" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573550" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 10 Jun 2011 13:57:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2404" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573152" + }, + { + "expires": "Sat, 10 Nov 2012 04:52:41 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 02 Jun 2011 21:47:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "17489" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=352377" + }, + { + "expires": "Wed, 07 Nov 2012 15:33:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Tue, 31 Jul 2012 15:09:43 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "7708" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573550" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 23 Mar 2007 20:45:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "4035" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573550" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:19 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 03 Jun 2010 13:02:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1660" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=352377" + }, + { + "expires": "Wed, 07 Nov 2012 15:33:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 21 Jun 2012 18:52:41 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "11884" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=75841" + }, + { + "expires": "Sun, 04 Nov 2012 10:44:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 31 Oct 2012 21:41:52 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "17667" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=50037" + }, + { + "expires": "Sun, 04 Nov 2012 03:34:06 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 05 Jul 2012 20:15:36 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2092" + }, + { + "cneonction": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private, max-age=86400" + }, + { + "expires": "Sun, 04 Nov 2012 13:40:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:10 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 24 Jun 2009 19:31:51 GMT" + }, + { + "etag": "\"1506ccd-181-46d1d28b0d7c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cteonnt-length": "385" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "233" + }, + { + "ntcoent-length": "62" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 13 Jan 2011 15:17:04 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1870" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=86400" + }, + { + "expires": "Sun, 04 Nov 2012 13:40:10 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:10 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:10 GMT" + }, + { + "server": "Apache" + }, + { + "last-modified": "Wed, 24 Jun 2009 19:31:51 GMT" + }, + { + "etag": "\"1506ccd-181-46d1d28b0d7c0\"" + }, + { + "accept-ranges": "bytes" + }, + { + "cteonnt-length": "385" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "74" + }, + { + "ntcoent-length": "62" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:40:10 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1866" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=604800" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:40:10 GMT" + }, + { + "expires": "Sat, 10 Nov 2012 13:40:10 GMT" + }, + { + "last-modified": "Tue, 31 Jul 2012 23:02:57 GMT" + }, + { + "server": "ECS (lhr/4BF1)" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "35" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Thu, 15 Dec 2011 19:05:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=52304" + }, + { + "expires": "Sun, 04 Nov 2012 04:11:53 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:09 GMT" + }, + { + "content-length": "42039" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:14:45 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "66" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=71036" + }, + { + "expires": "Sun, 04 Nov 2012 09:24:08 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "247" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64954" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:46 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2289" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64924" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "2443" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=64924" + }, + { + "expires": "Sun, 04 Nov 2012 07:42:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "server": "Apache" + }, + { + "vary": "Cookie" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:38:24 +0000" + }, + { + "cache-control": "max-age=132, must-revalidate" + }, + { + "keep-alive": "timeout=60, max=940" + }, + { + "connection": "Keep-Alive" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 18 Mar 2009 18:50:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "188" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=349116" + }, + { + "expires": "Wed, 07 Nov 2012 14:38:48 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 18 Mar 2009 18:50:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "106" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=349122" + }, + { + "expires": "Wed, 07 Nov 2012 14:38:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 18 Mar 2009 18:50:08 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "131" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=349122" + }, + { + "expires": "Wed, 07 Nov 2012 14:38:54 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 09 Sep 2009 16:10:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "351" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=349157" + }, + { + "expires": "Wed, 07 Nov 2012 14:39:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Wed, 09 Sep 2009 16:10:20 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "224" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/png" + }, + { + "cache-control": "private, max-age=349157" + }, + { + "expires": "Wed, 07 Nov 2012 14:39:29 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "872" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs38FVrcF5/ZLq6rynLbPIrzBMgf6gCZEFYbnEyqJwHBZC0garfrvMOIs+B939ykqVLVck4XSTGQIMvPdVthDcyttnh/a+rfKsxItpUfG2D5pA4KGuH2gGpHenDN3B0M6eEi6BWcidf0I+ZlqmL9bIpDHIKu64kT0YghPKjDoejnlzus5jQeqqP4igBfBMSRX3hgEHkgrccVaMsrutxL45k8Cggfg==; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:40:12 GMT; Path=/" + }, + { + "x-proc-data": "pd4-bgas03-2" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 03:08:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "18011" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573549" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "303" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "location": "/dcsj5tb4n100000sl76culaeo_4f3w/dcs.gif?dcsredirect=112&dcstlh=0&dcstlv=0&dcsdat=1351950012922&dcssip=www.nytimes.com&dcsuri=/pages/nyregion/index.html&dcsref=http://www.nytimes.com/2012/11/04/education/edlife/a-new-kind-of-tutoring-aims-to-make-students-smarter.html%3Fpagewanted=4%26ref=science&WT.co_f=130.129.68.73-2680109824.30259656&WT.vt_sid=130.129.68.73-2680109824.30259656.1351949959620&WT.tz=-4&WT.bh=9&WT.ul=en-US&WT.cd=24&WT.sr=1366x768&WT.jo=Yes&WT.ti=New%20York%20Region%20News%20-%20The%20New%20York%20Times&WT.js=Yes&WT.jv=1.7&WT.ct=unknown&WT.bs=994x649&WT.fi=No&WT.tv=1.0.7&WT.dl=0&WT.es=www.nytimes.com/pages/nyregion/index.html&WT.cg_n=N.Y./Region&WT.z_rcgn=N.Y./Region&WT.z_gpt=Section%20Front&WT.z_nyts=0Ma.K9EWB.dlLDXrmvxADeHI4U72bYMorSdeFz9JchiALJvjis/thrUYV.Ynx4rkFI&WT.z_nytd=&WT.z_rmid=007f010022166047bee9002b&WT.z_ref=nytimes.com&WT.rv=0&WT.mc_ev=&WT.vt_f_tlv=&WT.vt_f_tlh=1351950010&WT.vt_f_d=&WT.vt_f_s=&WT.vt_f_a=&WT.vt_f=" + }, + { + "content-length": "0" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAAEAAAAmLwAAJEelVCHHpVQ9r0AALkelVCSHpVQ+r0AAJ0elVCdHpVQ970AALwelVC8HpVQAQAAAHhHAAC8HpVQhx6VUAAAAAA-; path=/; expires=Thu, 10-Dec-2015 10:27:34 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 03:06:34 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "25015" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573549" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 03:06:11 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "25206" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=573549" + }, + { + "expires": "Sat, 10 Nov 2012 04:59:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "304" + }, + { + "x-amz-id-2": "d90CCR9lSoaaNwupUMIdb/ey0mevoBrnI3ZRtI8HHFRBEUtsLjtNMBWb2X6DprZz" + }, + { + "x-amz-request-id": "D6FC61A73C17CF70" + }, + { + "date": "Sat, 03 Nov 2012 13:40:14 GMT" + }, + { + "cache-control": "max-age=10" + }, + { + "content-encoding": "gzip" + }, + { + "last-modified": "Sat, 03 Nov 2012 13:35:29 GMT" + }, + { + "etag": "\"8254326a395317db7b197564fa83e476\"" + }, + { + "accept-ranges": "bytes" + }, + { + "content-type": "" + }, + { + "content-length": "92155" + }, + { + "server": "AmazonS3" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:40:13 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAAEAAAAmLwAAJEelVCHHpVQ9r0AALkelVCSHpVQ+r0AAJ0elVCdHpVQ970AAL0elVC8HpVQAQAAAHhHAAC9HpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:40:13 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 07:39:41 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=300" + }, + { + "expires": "Sat, 03 Nov 2012 13:45:12 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:12 GMT" + }, + { + "content-length": "4073" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/png" + }, + { + "date": "Sat, 03 Nov 2012 13:40:13 GMT" + }, + { + "etag": "\"fb5af56cb67780c01fb3516e7c3f74e3\"" + }, + { + "expires": "Sun, 03 Nov 2013 13:40:13 GMT" + }, + { + "last-modified": "Wed, 04 Apr 2012 20:38:25 GMT" + }, + { + "server": "ECS (lhr/4BA4)" + }, + { + "x-amz-id-2": "cBUUBPPZMto6skduFezdQ+9bNRCuwVjOvgFgohhb4PfZdlrYG33n3GM2BJ25YTtq" + }, + { + "x-amz-request-id": "6758CF2C16F8B0C0" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "1662" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:40:13 GMT" + }, + { + "etag": "\"0940a52ad7b3435f775918b80b088f27\"" + }, + { + "expires": "Sun, 03 Nov 2013 13:40:13 GMT" + }, + { + "last-modified": "Thu, 30 Sep 2010 12:29:59 GMT" + }, + { + "server": "ECS (lhr/4BCC)" + }, + { + "x-amz-id-2": "jDnDMjao+nUL4vfffUU3TFPTyN1KxJt9Dy6uCIra3CbwdS9wgqVrVK02Lhf++2Kk" + }, + { + "x-amz-request-id": "296BB691837A53B5" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "980" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:40:13 GMT" + }, + { + "etag": "\"7e3ff7f7848a81a63b6e2e0bfb394799\"" + }, + { + "expires": "Sun, 03 Nov 2013 13:40:13 GMT" + }, + { + "last-modified": "Sun, 12 Jun 2011 15:43:21 GMT" + }, + { + "server": "ECS (lhr/4BA1)" + }, + { + "x-amz-id-2": "QHLqCpOps7vUVMXN1QzHCNBpV3eM2RaV2CNFSW7QQ5BQSiaY2U04JVbdV76t6uPA" + }, + { + "x-amz-request-id": "4E56272125A99862" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "2607" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:40:13 GMT" + }, + { + "etag": "\"3ff974032fd77223fd059c6d234ebb43\"" + }, + { + "expires": "Sun, 03 Nov 2013 13:40:13 GMT" + }, + { + "last-modified": "Tue, 14 Jun 2011 16:57:49 GMT" + }, + { + "server": "ECS (lhr/4BDF)" + }, + { + "x-amz-id-2": "q0tabYbFY5+80zmAw4/5X92+LUMhsasmJRWZU8wZxF7S+TYVyMgxcBM47nT2KV2t" + }, + { + "x-amz-request-id": "5C17C42AD2E36B99" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "3219" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:40:13 GMT" + }, + { + "etag": "\"ac105110a13a3d24f2b5d502fb0db4e8\"" + }, + { + "expires": "Sun, 03 Nov 2013 13:40:13 GMT" + }, + { + "last-modified": "Tue, 16 Jun 2009 22:22:00 GMT" + }, + { + "server": "ECS (lhr/4BAD)" + }, + { + "x-amz-id-2": "AlVWqZvxNaFzFrxq+Lo/jRl878iwJzLMeSmnDalUQWo33DvFg3BUtTZnEF+yRJ5W" + }, + { + "x-amz-request-id": "F6C83DE008C7DEFA" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "1673" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "cache-control": "max-age=31536000" + }, + { + "content-type": "image/jpeg" + }, + { + "date": "Sat, 03 Nov 2012 13:40:13 GMT" + }, + { + "etag": "\"6c157f6f56910c50a03faa81d54546bd\"" + }, + { + "expires": "Sun, 03 Nov 2013 13:40:13 GMT" + }, + { + "last-modified": "Tue, 06 Sep 2011 20:24:40 GMT" + }, + { + "server": "ECS (lhr/4BAC)" + }, + { + "x-amz-id-2": "KFCqXFOHRJbWl2rZ7FfvRitLrhcAZnqUIfhUqkDIDZOQB0cgxkSjAlC9Qh0pOvZ3" + }, + { + "x-amz-request-id": "8BF259D47606A786" + }, + { + "x-cache": "HIT" + }, + { + "content-length": "2437" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:40:13 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:40:13 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=271 t=1351950013983899" + }, + { + "x-served-by": "beacon-a002.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.7.67" + }, + { + "date": "Sat, 03 Nov 2012 13:40:14 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:52:17 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "15613" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=564661" + }, + { + "expires": "Sat, 10 Nov 2012 02:31:18 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 03 Apr 2012 15:22:24 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "1955" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=299" + }, + { + "expires": "Sat, 03 Nov 2012 13:45:16 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 02:54:40 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "14642" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:54:59 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "15613" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=547394" + }, + { + "expires": "Fri, 09 Nov 2012 21:43:31 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MA4.kVz1KQmzDXrmvxADeHK.rUS.yFrOJdeFz9JchiALJvjis/thrUYV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "216" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "application/x-javascript" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/1.0.0" + }, + { + "set-cookie": "nyt-m=8FF27B7C7E22BE437F4E72563691B5C2&e=i.1354338000&t=i.10&v=i.3&l=l.25.2802408197.2634689326.1254883451.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.3.0.0.0&pr=l.4.9.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.1254883451.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:40:17 GMT; path=/; domain=.nytimes.com" + }, + { + "content-length": "113" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "cache-control": "max-age=0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:01 GMT" + }, + { + "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\"" + }, + { + "pragma": "no-cache" + }, + { + "server": "nginx/0.7.59" + }, + { + "content-length": "43" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "303" + }, + { + "cache-control": "private" + }, + { + "date": "Sat, 03 Nov 2012 13:40:16 GMT" + }, + { + "location": "http://d1aivi5dp2wry5.cloudfront.net/pixel.gif" + }, + { + "p3p": "CP=\"NOI PSAo OUR IND COM NAV STA\"" + }, + { + "server": "Microsoft-IIS/7.0" + }, + { + "x-aspnet-version": "4.0.30319" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "content-length": "0" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MP9kmlu11B5nDXrmvxADeHK.rUS.yFrOJdeFz9JchiAKfXJAEEJyUmIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-type": "text/html" + }, + { + "connection": "close" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "59" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "45" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "server": "Apache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "NYT-S=0MP9kmlu11B5nDXrmvxADeHK.rUS.yFrOJdeFz9JchiAKfXJAEEJyUmIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "ntcoent-length": "50" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:54:29 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "7020" + }, + { + "cneonction": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=76680" + }, + { + "expires": "Sun, 04 Nov 2012 10:58:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:49:48 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "41440" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:50:15 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "53346" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:48:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "55860" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:49:19 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "46030" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:51:50 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "25431" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:52:12 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "27683" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:50:56 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "71084" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/html; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1966" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "last-modified": "Sat, 03 Nov 2012 05:51:23 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-length": "34384" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/jpeg" + }, + { + "cache-control": "private, max-age=579064" + }, + { + "expires": "Sat, 10 Nov 2012 06:31:21 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "1024" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "server": "Apache" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "text/html" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "521" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0M6GemS05ruUDDXrmvxADeHAjAqSvifpeXdeFz9JchiAKfXJAEEJyUmIV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/1.0.10" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "content-type": "application/json" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-length": "156" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MMaQ/2qmmFHvDXrmvxADeHAjAqSvifpeXdeFz9JchiAIcUoUNnYFX3YV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "cteonnt-length": "45" + }, + { + "connection": "close" + }, + { + "content-type": "text/html" + }, + { + "content-length": "59" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "server": "nginx/1.0.10" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/json" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5623" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"" + }, + { + "content-type": "text/javascript; charset=UTF-8" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "server": "cafe" + }, + { + "cache-control": "private" + }, + { + "content-length": "979" + }, + { + "x-xss-protection": "1; mode=block" + }, + { + "x-frame-options": "ALLOWALL" + }, + { + "age": "3217" + }, + { + "content-disposition": "attachment" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache-Coyote/1.1" + }, + { + "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\"" + }, + { + "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0" + }, + { + "pragma": "no-cache" + }, + { + "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:40:18 GMT; Path=/" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "content-type": "image/gif" + }, + { + "transfer-encoding": "chunked" + }, + { + "connection": "keep-alive" + }, + { + "keep-alive": "timeout=20" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "no-cache" + }, + { + "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\"" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "set-cookie": "rts_AAAA=MLs3MV9rcF5/e8raSsB8J1a8xoyhfqgGdE1oaHcypJ43DeCuFAmr4KFNP2NyUKmpJDKN5oHAaw4FLg6p/xU87LpGBP1V8Vwc/u8nqIWD9h6mituy2I3ef/nmfXXys59Ro9/kQ77nLnGIV6iKi6h89ib3bNEkAgz8RVtHEqb8hpvCshkDOJUx9+7dGislj1zxURVYlAk37LbXfBKtqErQegJsJj8=; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:40:18 GMT; Path=/" + }, + { + "x-proc-data": "pd4-bgas09-2" + }, + { + "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\"" + }, + { + "server": "RSI" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "expires": "Thu, 01 Jan 1970 00:00:00 GMT" + }, + { + "content-type": "application/javascript;charset=UTF-8" + }, + { + "transfer-encoding": "chunked" + }, + { + "content-encoding": "gzip" + }, + { + "vary": "Accept-Encoding" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "connection": "close" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "server": "Microsoft-IIS/6.0" + }, + { + "x-powered-by": "ASP.NET" + }, + { + "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAAEAAAAmLwAAJEelVCHHpVQ9r0AALkelVCSHpVQ+r0AAJ0elVCdHpVQ970AAMIelVC8HpVQAQAAAHhHAADCHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:40:18 GMT" + }, + { + "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\"" + }, + { + "pragma": "no-cache" + }, + { + "expires": "-1" + }, + { + "cache-control": "no-cache" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "67" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "server": "Sun-ONE-Web-Server/6.1" + }, + { + "ntcoent-length": "1068" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/json" + }, + { + "cache-control": "private" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "5623" + }, + { + "connection": "keep-alive" + }, + { + "x-powered-by": "PHP/5.2.9" + }, + { + "content-type": "text/html" + }, + { + "set-cookie": "NYT-S=0MMaQ/2qmmFHvDXrmvxADeHAjAqSvifpeXdeFz9JchiAIcUoUNnYFX3YV.Ynx4rkFI; path=/; domain=.nytimes.com" + }, + { + "expires": "Thu, 01 Dec 1994 16:00:00 GMT" + }, + { + "cache-control": "no-cache" + }, + { + "pragma": "no-cache" + }, + { + "transfer-encoding": "chunked" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "nncoection": "close" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 12 Oct 2012 00:14:49 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "content-encoding": "gzip" + }, + { + "content-length": "13551" + }, + { + "cneonction": "close" + }, + { + "content-type": "image/gif" + }, + { + "cache-control": "private, max-age=68002" + }, + { + "expires": "Sun, 04 Nov 2012 08:33:40 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:18 GMT" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "Apache" + }, + { + "last-modified": "Sat, 03 Nov 2012 07:39:41 GMT" + }, + { + "accept-ranges": "bytes" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-encoding": "gzip" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/x-javascript" + }, + { + "cache-control": "private, max-age=300" + }, + { + "expires": "Sat, 03 Nov 2012 13:45:17 GMT" + }, + { + "date": "Sat, 03 Nov 2012 13:40:17 GMT" + }, + { + "content-length": "4073" + }, + { + "connection": "keep-alive" + }, + { + "cneonction": "close" + } + ] + }, + { + "headers": [ + { + ":status": "204" + }, + { + "cache-control": "private, no-cache, no-store" + }, + { + "content-length": "0" + }, + { + "content-type": "image/gif" + }, + { + "date": "Sat, 03 Nov 2012 13:40:19 GMT" + }, + { + "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\"" + }, + { + "server": "Apache" + }, + { + "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:40:19 GMT; domain=.krxd.net" + }, + { + "x-request-time": "D=259 t=1351950019348818" + }, + { + "x-served-by": "beacon-a002.krxd.net" + }, + { + "connection": "keep-alive" + } + ] + }, + { + "headers": [ + { + ":status": "200" + }, + { + "server": "nginx/0.7.67" + }, + { + "date": "Sat, 03 Nov 2012 13:40:19 GMT" + }, + { + "content-type": "image/gif" + }, + { + "content-length": "43" + }, + { + "connection": "close" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_31.json b/jetty-http2/http2-hpack/src/test/resources/data/story_31.json new file mode 100644 index 00000000000..62f43e25509 --- /dev/null +++ b/jetty-http2/http2-hpack/src/test/resources/data/story_31.json @@ -0,0 +1,4555 @@ +{ + "cases": [ + { + "seqno": 0, + "headers": [ + { + "content-length": "522" + }, + { + "x-content-type-options": "nosniff" + }, + { + ":status": "200" + }, + { + "expires": "Tue, 21 May 2013 19:18:33 GMT" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:20 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "public, max-age=17216869" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "IVe/SwucJuBsLtVHWJw2PMdOTOxuEWUir5igQNThkTg=" + } + ] + }, + { + "seqno": 1, + "headers": [ + { + "x-cnection": "close" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Sun, 12 May 2013 06:59:14 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "123" + }, + { + "last-modified": "Tue, 24 Apr 2012 22:13:35 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=16394910" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "95tUymdadFLd8Dpml8VnOoUG7KhisOwk74Kd/aIGfU0=" + } + ] + }, + { + "seqno": 2, + "headers": [ + { + "content-length": "14684" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:44:39 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:37:35 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31067635" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "Qc0GcUiwi3io8aSRIdXaahYr6KKhphvV6NlN8vo/bD4=" + } + ] + }, + { + "seqno": 3, + "headers": [ + { + "content-length": "14438" + }, + { + "x-content-type-options": "nosniff" + }, + { + ":status": "200" + }, + { + "expires": "Mon, 19 Aug 2013 00:53:24 GMT" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:23 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "public, max-age=24926560" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "7exUqkoZxtfLseR1zLxJlXnpYK6MOognZuCKx7drdRo=" + } + ] + }, + { + "seqno": 4, + "headers": [ + { + "content-length": "17475" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 18:31:11 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 29 Oct 2012 17:08:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31124427" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "eRvyJLXIvW3Vu9d+m439v+LGKqXiLSKmz7w9/xMAUpc=" + } + ] + }, + { + "seqno": 5, + "headers": [ + { + "content-length": "44191" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:44:39 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 22:55:27 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31067635" + }, + { + "date": "Sat, 03 Nov 2012 12:50:44 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "14hoEcywNNMBIVUS5B7AD7RDGiDvJ4BGeOVgJbBDzf0=" + } + ] + }, + { + "seqno": 6, + "headers": [ + { + "content-length": "754" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 16 Oct 2013 14:03:31 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 12 Oct 2012 18:34:48 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=29985162" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "41/HuGcFNMmys4cvGKlBeylojdVDP4+VBIf1giu3eNQ=" + } + ] + }, + { + "seqno": 7, + "headers": [ + { + "x-cnection": "close" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:40:10 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "2349" + }, + { + "last-modified": "Thu, 25 Oct 2012 16:05:53 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31067361" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "oKQwv0JLYost+zqlv8x+C7MEL7zRBbeMomoc54M5RZY=" + } + ] + }, + { + "seqno": 8, + "headers": [ + { + "content-length": "2626" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 03:00:19 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:08:50 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068570" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "zh8tRHKFtERIZ+K/eGiM1utm1H66OnOj1qwPAN7Ck9A=" + } + ] + }, + { + "seqno": 9, + "headers": [ + { + "content-length": "8036" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:33:09 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 28 Sep 2012 15:01:14 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31066940" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "pricqIchHztHxKAQSidQiwGmRf62vAL6I7Oi0r/Ki08=" + } + ] + }, + { + "seqno": 10, + "headers": [ + { + "content-length": "36302" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:58:39 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:42:19 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068470" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "Kur2FUUQjAQ0yPQJC9fvK56/+LWZHvyQF6Ce2Fuaf2k=" + } + ] + }, + { + "seqno": 11, + "headers": [ + { + "content-length": "8230" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 27 Aug 2013 06:59:08 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:02:51 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25639699" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "wk2MWysJhw3Et7CRGMA1sE9HWuyzy8oCvtT2V7iPXeg=" + } + ] + }, + { + "seqno": 12, + "headers": [ + { + "content-length": "4878" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:59:38 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:38:44 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068529" + }, + { + "date": "Sat, 03 Nov 2012 12:50:49 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "GMzzyj0B89LYf1zKH9hqxZekz5mYTmsuxwLugWyc2Gg=" + } + ] + }, + { + "seqno": 13, + "headers": [ + { + "content-length": "1814" + }, + { + ":status": "200" + }, + { + "content-transfer-encoding": "binary" + }, + { + "expires": "Sat, 10 Nov 2012 04:37:48 GMT" + }, + { + "last-modified": "Sat, 03 Nov 2012 04:37:48 GMT" + }, + { + "connection": "Keep-Alive" + }, + { + "cache-control": "max-age=575215, public, no-transform, must-revalidate" + }, + { + "date": "Sat, 03 Nov 2012 12:50:53 GMT" + }, + { + "nncoection": "close" + }, + { + "content-type": "application/ocsp-response" + } + ] + }, + { + "seqno": 14, + "headers": [ + { + "content-length": "43" + }, + { + ":status": "200" + }, + { + "x-fb-metrics": "{\"w\":53,\"r\":26,\"q\":0,\"a\":25}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.74.89.23" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:50:54 GMT" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "7iLjsQVXsunUKXe3NlV2ytaBGzQ0VHCkMX/J6rEuB6Y=" + } + ] + }, + { + "seqno": 15, + "headers": [ + { + "content-length": "1155" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:46:08 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 15:06:53 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31067714" + }, + { + "date": "Sat, 03 Nov 2012 12:50:54 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "ur+THlFHeLotsmDlQWYPw2GRELyvg28JmE0JYVt56uo=" + } + ] + }, + { + "seqno": 16, + "headers": [ + { + "content-length": "516" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 04 Sep 2013 02:55:58 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 31 Aug 2012 22:13:28 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=26316304" + }, + { + "date": "Sat, 03 Nov 2012 12:50:54 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "6/fKHkRtBpT4oqBg33tFHk2pO6SDZlUG11Uq4/AlUIE=" + } + ] + }, + { + "seqno": 17, + "headers": [ + { + "content-length": "232" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Mon, 21 Oct 2013 14:44:35 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sat, 21 Apr 2012 07:03:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=30419619" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "XtTsONeGHGs/1vRRv8cvNY1ciB3XqlrvnTq2GZXvnqM=" + } + ] + }, + { + "seqno": 18, + "headers": [ + { + "x-cnection": "close" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:33:09 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "content-length": "400" + }, + { + "last-modified": "Fri, 07 Sep 2012 15:18:40 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31066933" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "E2JBYTapyXFjxTTVqkrekTVKDp1lDQQT/7YxcxfNU2U=" + } + ] + }, + { + "seqno": 19, + "headers": [ + { + "content-length": "35766" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:14 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:41:45 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068980" + }, + { + "date": "Sat, 03 Nov 2012 12:50:54 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "iPbLdjapQzRoatbOUDrN+exDj8EPHJAcsZ48pVtprtA=" + } + ] + }, + { + "seqno": 20, + "headers": [ + { + "content-length": "10902" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:33:40 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 14:34:50 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31066965" + }, + { + "date": "Sat, 03 Nov 2012 12:50:55 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "0ci0R5R2ivIVCRrwtG507Eej+LTK8dUL8dIiZp70+dU=" + } + ] + }, + { + "seqno": 21, + "headers": [ + { + "content-length": "4676" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 08:36:24 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:38:28 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31088728" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "P2Bq0ebVXjtf8GyQp1HHux8NxlftUMXZuY8XF+yaOVo=" + } + ] + }, + { + "seqno": 22, + "headers": [ + { + "content-length": "20791" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:45:10 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:37:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31067654" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "yHzV/c0w3ZyInkRbLCDrA0t5adSMyAG4prBOk+i+t6Y=" + } + ] + }, + { + "seqno": 23, + "headers": [ + { + "content-length": "11113" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:34:04 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sun, 28 Oct 2012 14:34:47 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31066988" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "u363OvKFmnm717JBUXA5ePB8Ts0ppRI7+eEJwOOep6w=" + } + ] + }, + { + "seqno": 24, + "headers": [ + { + "content-length": "43" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 28 Aug 2013 14:37:09 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:02:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25753573" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "Yty+Te4OzfswtmjzbJmJZaybyM0hxXiRU2NtHEbDuPE=" + } + ] + }, + { + "seqno": 25, + "headers": [ + { + "content-length": "571" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 28 Aug 2013 14:41:07 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:24 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25753811" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "yKFyrxwqBiumMPfWvv4morUUsmz9djZtSdmCoQMnchs=" + } + ] + }, + { + "seqno": 26, + "headers": [ + { + "content-length": "43" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 28 Aug 2013 14:40:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25753770" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "HbryxnP7HNa7kdTChA6BppSjLQw0gz9ZzESCqEH3/9k=" + } + ] + }, + { + "seqno": 27, + "headers": [ + { + "content-length": "12817" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Thu, 05 Sep 2013 18:18:17 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Tue, 28 Aug 2012 01:20:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=26458041" + }, + { + "date": "Sat, 03 Nov 2012 12:50:56 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "edgqdu1lFmUW32Et2hHoiAsp9kFIch8QDiciO71cQ4w=" + } + ] + }, + { + "seqno": 28, + "headers": [ + { + "content-length": "11688" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:27 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:09:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068990" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "rXXtxI3fPgNHe6wKIDRBR0xjttUNeG+BDQM8QfKQa+A=" + } + ] + }, + { + "seqno": 29, + "headers": [ + { + "content-length": "35165" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:59:38 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:06:47 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068521" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "fUJ2Nc9qJdBC1AnYFA5Vs1f7ozv+i/PTKO+Vep0A0HQ=" + } + ] + }, + { + "seqno": 30, + "headers": [ + { + "content-length": "1028" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 30 Oct 2013 13:15:07 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:07:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31191849" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "s9ZmJKnYGlEjIGo8xQzxlhVM4nilGHgcv1fhK1Z7F1w=" + } + ] + }, + { + "seqno": 31, + "headers": [ + { + "content-length": "47844" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:27 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:07:08 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068990" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "hMQvA7xhuAspt5fOxedr0fWzQZNLkyizVtlmspzgVG8=" + } + ] + }, + { + "seqno": 32, + "headers": [ + { + "content-length": "42391" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 23:54:49 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 29 Oct 2012 19:17:24 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31143832" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "1EkJKYLfWucaDVhZCEVAAo57HpAH7rvF4r9IwDXM2B8=" + } + ] + }, + { + "seqno": 33, + "headers": [ + { + "content-length": "13181" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:27 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:10:32 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068989" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "dO6OKUf38jDdtAnTrM28wZTBz9Y5hU/0EJdd1CkWGDs=" + } + ] + }, + { + "seqno": 34, + "headers": [ + { + "content-length": "23736" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Sat, 02 Nov 2013 20:50:17 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 02 Nov 2012 19:03:57 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31478360" + }, + { + "date": "Sat, 03 Nov 2012 12:50:57 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "IlZ4dyc3v7fqrfiamqJbFeFTWRkUvEUs2L8KLXNa+5o=" + } + ] + }, + { + "seqno": 35, + "headers": [ + { + "content-length": "12969" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Fri, 01 Nov 2013 21:39:03 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 01 Nov 2012 20:35:28 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31394885" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "REVz0k4Gud7bedzv9KSTG2i1KOporb0T14mWht95MIE=" + } + ] + }, + { + "seqno": 36, + "headers": [ + { + "content-length": "8457" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 08:36:26 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:06:44 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31088728" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "VKvuYL/9rqvjXh7mr8LjSJmcgQLZ/a+Ztqj2aUsPacc=" + } + ] + }, + { + "seqno": 37, + "headers": [ + { + "content-length": "43" + }, + { + ":status": "200" + }, + { + "x-fb-metrics": "{\"w\":26,\"r\":18,\"q\":0,\"a\":30}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.86.49" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "egJridVr0Ohgw3QbFe66p8hTV/ZDa+ldtrrj55f1Dwg=" + } + ] + }, + { + "seqno": 38, + "headers": [ + { + "content-length": "43" + }, + { + ":status": "200" + }, + { + "x-fb-metrics": "{\"w\":15,\"r\":74,\"q\":0,\"a\":21}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.212.85" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "7JVbUHGoJcLzIbHgkJPv0DSBycKYYPPorUc0i6OdRw8=" + } + ] + }, + { + "seqno": 39, + "headers": [ + { + "content-length": "10334" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-metrics": "{\"w\":33,\"r\":14,\"q\":0,\"a\":27}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.203.85" + }, + { + ":status": "200" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "x-fb-debug": "SHFiC3r5rPZSoyQ6AT4o7Lrz58o2i0cRMRoLoKKAVLc=" + } + ] + }, + { + "seqno": 40, + "headers": [ + { + "content-length": "79019" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-metrics": "{\"w\":47,\"r\":27,\"q\":0,\"a\":24}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.121.55" + }, + { + ":status": "200" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "x-fb-debug": "B8TQ25HLrpUM+2nuhej+798G7ib2rXsLxKDRmmd6364=" + } + ] + }, + { + "seqno": 41, + "headers": [ + { + "content-length": "43" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 21 May 2013 19:18:35 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:05 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=17216856" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "q1YlNQFhUrIi0HF88gF/s47itTMC0ALVS2i6Xo/eSFQ=" + } + ] + }, + { + "seqno": 42, + "headers": [ + { + "content-length": "43" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 21 May 2013 19:18:34 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:20 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=17216855" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "OOKrpYeJ1K2euVWUg0h3X4OLDU+bPXAhHe2ZbKmaIIo=" + } + ] + }, + { + "seqno": 43, + "headers": [ + { + "content-length": "55530" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:27 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:42:28 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068989" + }, + { + "date": "Sat, 03 Nov 2012 12:50:58 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "BWYgCEbzeWyERD5oPP51t1mG+xnS0km1r6TZrds9BdY=" + } + ] + }, + { + "seqno": 44, + "headers": [ + { + "content-length": "67" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-metrics": "{\"w\":47,\"r\":27,\"q\":0,\"a\":24}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.121.55" + }, + { + ":status": "200" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "6DDnMStngO3Ec4qHVJLnouT/OjWIKWOh3p7X19lwA2E=" + } + ] + }, + { + "seqno": 45, + "headers": [ + { + "content-length": "67" + }, + { + ":status": "200" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "DY+dO6Fs6HOjJLzXfO2vzcoACugopwtj+ZfSFe3+0Io=" + } + ] + }, + { + "seqno": 46, + "headers": [ + { + "content-length": "6332" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 15 Oct 2013 04:49:02 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Mon, 15 Oct 2012 01:19:28 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=29865483" + }, + { + "date": "Sat, 03 Nov 2012 12:50:59 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "U3t5ojZAXSlz/rftvVXMdi+dQaAlCxv95u4nFdmaOpU=" + } + ] + }, + { + "seqno": 47, + "headers": [ + { + "content-length": "1025" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 21 May 2013 19:18:34 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:19 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=17216854" + }, + { + "date": "Sat, 03 Nov 2012 12:51:00 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "WkN9kzT0IbJnmPVAe/JpiO1KA3sDm5JiLNu+peaU22E=" + } + ] + }, + { + "seqno": 48, + "headers": [ + { + "content-length": "7905" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 30 Oct 2013 13:12:25 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:38:51 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31191685" + }, + { + "date": "Sat, 03 Nov 2012 12:51:00 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "flUDwRXAcKGlCZV+B6xp1kix2zMM2jCaLr8GXWfOS9o=" + } + ] + }, + { + "seqno": 49, + "headers": [ + { + "content-length": "960" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 28 Aug 2013 14:36:20 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 07 Jun 2012 20:17:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25753518" + }, + { + "date": "Sat, 03 Nov 2012 12:51:02 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "s2bSrOgSOrnc1I2Y+hCmZNjO4JKRAsJvvEShk7xvQh0=" + } + ] + }, + { + "seqno": 50, + "headers": [ + { + "content-length": "1421" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 28 Aug 2013 14:36:47 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Fri, 13 Jul 2012 13:05:49 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25753545" + }, + { + "date": "Sat, 03 Nov 2012 12:51:02 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "dSqFMj3BQam7KrjoHsDUySNYx2e/ZA4jk+iLwQD5q+M=" + } + ] + }, + { + "seqno": 51, + "headers": [ + { + "content-length": "3977" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 30 Oct 2013 05:00:35 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:41:38 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31162173" + }, + { + "date": "Sat, 03 Nov 2012 12:51:02 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "if1LyEGCEK6E/tHFIYqTdcReGf2YlH/8CNcvt0MSb5c=" + } + ] + }, + { + "seqno": 52, + "headers": [ + { + "content-length": "316" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 27 Aug 2013 03:46:29 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25628126" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "0MQqsPt7SaQdEz9msJEk0wieC0zyyvfgvjy4gscfRm4=" + } + ] + }, + { + "seqno": 53, + "headers": [ + { + "content-length": "6779" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 09 May 2012 22:55:50 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 54, + "headers": [ + { + "content-length": "7899" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Mon, 14 May 2012 09:15:54 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 55, + "headers": [ + { + "content-length": "8961" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "last-modified": "Fri, 10 Aug 2012 23:04:25 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 56, + "headers": [ + { + "content-length": "7270" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "last-modified": "Thu, 17 May 2012 17:02:26 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 57, + "headers": [ + { + "content-length": "10284" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 14 Sep 2012 13:43:01 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 58, + "headers": [ + { + "content-length": "6932" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 15 May 2012 16:53:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 59, + "headers": [ + { + "content-length": "19404" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "last-modified": "Fri, 13 Jul 2012 21:38:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 60, + "headers": [ + { + "content-length": "43" + }, + { + ":status": "200" + }, + { + "x-fb-metrics": "{\"w\":23,\"r\":24,\"q\":0,\"a\":31}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.204.89" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "mhzgPOTS+rD7XyjD1gp3zWldoiZpmeeyK0sWCXxCmL8=" + } + ] + }, + { + "seqno": 61, + "headers": [ + { + "content-length": "43" + }, + { + ":status": "200" + }, + { + "x-fb-metrics": "{\"w\":13,\"r\":137,\"q\":0,\"a\":23}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.167.53" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "content-type": "image/gif" + }, + { + "x-fb-debug": "uWC6Yw5Jjt8tp6GMW/0c7q4sQiyN+cfsFumyrajMSLE=" + } + ] + }, + { + "seqno": 62, + "headers": [ + { + "content-length": "10334" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-metrics": "{\"w\":20,\"r\":43,\"q\":0,\"a\":30}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.165.52.67" + }, + { + ":status": "200" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "x-fb-debug": "K6O9zzGnsjkFUcjVnvogKEp8WyYKDD5/1SRA3JOqTz8=" + } + ] + }, + { + "seqno": 63, + "headers": [ + { + "content-length": "79019" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-metrics": "{\"w\":40,\"r\":33,\"q\":0,\"a\":22}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.10.79" + }, + { + ":status": "200" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "content-type": "image/jpeg" + }, + { + "x-fb-debug": "gU+KRCRWrUp+aETSVFA2+QqzJ57Mry5y8i9NZISRzV4=" + } + ] + }, + { + "seqno": 64, + "headers": [ + { + "content-length": "67" + }, + { + "content-encoding": "gzip" + }, + { + "x-fb-metrics": "{\"w\":40,\"r\":33,\"q\":0,\"a\":22}" + }, + { + "expires": "Thu, 1 Apr 2004 01:01:01 GMT" + }, + { + "x-fb-server": "10.164.10.79" + }, + { + ":status": "200" + }, + { + "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "2KYdrNd+vAjbaW2+l9lZ0c9qQnQQuLC0uV+aDWEfnEs=" + } + ] + }, + { + "seqno": 65, + "headers": [ + { + "content-length": "67" + }, + { + ":status": "200" + }, + { + "connection": "keep-alive" + }, + { + "date": "Sat, 03 Nov 2012 12:51:04 GMT" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "ltZY31wZe0x9jjXZ+/GQMCIZ6L+UzLcVFaj4Ye8cEag=" + } + ] + }, + { + "seqno": 66, + "headers": [ + { + "content-length": "32220" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Mon, 15 Oct 2012 15:37:08 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 67, + "headers": [ + { + "content-length": "105703" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Mon, 15 Oct 2012 15:38:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 68, + "headers": [ + { + "content-length": "36768" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 01 Nov 2012 01:55:42 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/gif" + } + ] + }, + { + "seqno": 69, + "headers": [ + { + "content-length": "119574" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 26 Oct 2012 09:41:12 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:03 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 70, + "headers": [ + { + "content-length": "659" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Sat, 11 May 2013 07:12:06 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=16309260" + }, + { + "date": "Sat, 03 Nov 2012 12:51:06 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/x-icon" + }, + { + "x-fb-debug": "yE8mx2kOMcI8Q4MtoKCXYAXv7xSMQBGufoB0y/qkYEs=" + } + ] + }, + { + "seqno": 71, + "headers": [ + { + "content-length": "6966" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "last-modified": "Thu, 17 May 2012 16:26:06 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 72, + "headers": [ + { + "content-length": "4501" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 06 Jul 2012 11:36:45 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 73, + "headers": [ + { + "content-length": "37432" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Mon, 04 Jun 2012 08:35:52 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 74, + "headers": [ + { + "content-length": "7198" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 15 May 2012 16:45:13 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 75, + "headers": [ + { + "content-length": "13454" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 31 May 2012 01:48:38 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 76, + "headers": [ + { + "content-encoding": "gzip" + }, + { + "transfer-encoding": "chunked" + }, + { + "access-control-allow-credentials": "true" + }, + { + ":status": "200" + }, + { + "connection": "keep-alive" + }, + { + "pragma": "no-cache" + }, + { + "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0" + }, + { + "date": "Sat, 03 Nov 2012 12:51:08 GMT" + }, + { + "access-control-allow-origin": "http://www.facebook.com" + }, + { + "content-type": "application/json" + } + ] + }, + { + "seqno": 77, + "headers": [ + { + "content-length": "19537" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "last-modified": "Tue, 19 Jun 2012 08:51:27 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 78, + "headers": [ + { + "content-length": "5842" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Mon, 14 May 2012 22:03:47 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 79, + "headers": [ + { + "content-length": "6973" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 22 May 2012 23:26:43 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 80, + "headers": [ + { + "content-length": "7263" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Mon, 11 Jun 2012 21:11:11 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 81, + "headers": [ + { + "content-length": "6222" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:09 GMT" + }, + { + "last-modified": "Tue, 15 May 2012 02:10:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 82, + "headers": [ + { + "content-length": "8005" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 13 Jul 2012 02:50:27 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 83, + "headers": [ + { + "content-length": "7949" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 31 Oct 2012 17:25:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 84, + "headers": [ + { + "content-length": "5850" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 23 May 2012 13:04:05 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 85, + "headers": [ + { + "content-length": "4860" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 18 May 2012 06:59:13 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 86, + "headers": [ + { + "content-length": "36615" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 08 Jun 2012 09:18:35 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 87, + "headers": [ + { + "content-length": "26180" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 01 Jun 2012 12:58:28 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 88, + "headers": [ + { + "content-length": "8551" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Wed, 16 May 2012 00:19:20 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 89, + "headers": [ + { + "content-length": "7021" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 18 May 2012 08:58:03 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 90, + "headers": [ + { + "content-length": "8126" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 17 May 2012 10:31:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 91, + "headers": [ + { + "content-length": "21780" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 20 Jul 2012 20:43:14 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 92, + "headers": [ + { + "content-length": "16109" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 08 Jun 2012 21:45:00 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 93, + "headers": [ + { + "content-length": "5248" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 15 May 2012 17:19:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 94, + "headers": [ + { + "content-length": "7600" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 15 May 2012 00:02:13 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 95, + "headers": [ + { + "content-length": "8148" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "last-modified": "Tue, 04 Sep 2012 05:25:17 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 96, + "headers": [ + { + "content-length": "23688" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:10 GMT" + }, + { + "last-modified": "Tue, 05 Jun 2012 16:58:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:10 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 97, + "headers": [ + { + "content-length": "32579" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 15 Jun 2012 23:21:31 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 98, + "headers": [ + { + "content-length": "36154" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Tue, 15 May 2012 16:53:04 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 99, + "headers": [ + { + "content-length": "8261" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Thu, 17 May 2012 16:15:19 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/jpeg" + } + ] + }, + { + "seqno": 100, + "headers": [ + { + "content-length": "34603" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "expires": "Sat, 17 Nov 2012 12:51:03 GMT" + }, + { + "last-modified": "Tue, 05 Jun 2012 19:33:30 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 101, + "headers": [ + { + "content-length": "19320" + }, + { + ":status": "200" + }, + { + "accept-ranges": "bytes" + }, + { + "last-modified": "Fri, 20 Jul 2012 22:33:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "max-age=1209600" + }, + { + "date": "Sat, 03 Nov 2012 12:51:09 GMT" + }, + { + "content-type": "image/png" + } + ] + }, + { + "seqno": 102, + "headers": [ + { + "content-length": "1589" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 30 Oct 2013 13:08:05 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sat, 27 Oct 2012 21:59:56 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31191410" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "cEr4CpqyPlutZEM5egM7EW1V/FoNLas8puqhILOyn6g=" + } + ] + }, + { + "seqno": 103, + "headers": [ + { + "content-length": "124" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 27 Aug 2013 05:04:30 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:34 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25632795" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "SjbWzWIhc5uDeUgKzkah4oVawEfOfsqgn79tJvLiODA=" + } + ] + }, + { + "seqno": 104, + "headers": [ + { + "content-length": "178" + }, + { + "x-content-type-options": "nosniff" + }, + { + ":status": "200" + }, + { + "expires": "Tue, 27 Aug 2013 06:45:13 GMT" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:02:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + "cache-control": "public, max-age=25638838" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "8BYYADIiLWZPRqrmghOTJnnu5b75InjLJYums29XQC4=" + } + ] + }, + { + "seqno": 105, + "headers": [ + { + "content-length": "3403" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 11:39:02 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Fri, 26 Oct 2012 21:42:07 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31099667" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "rg/3x10ePyW5+Yv14okaeMgQpdIDitUpRdeQlHd62wU=" + } + ] + }, + { + "seqno": 106, + "headers": [ + { + "content-length": "3794" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 09:12:42 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:11:34 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31090886" + }, + { + "date": "Sat, 03 Nov 2012 12:51:16 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "+G0d7Y1/nAK76h5l1ygZcgFyqkHdYYjzu9bN8TThTW0=" + } + ] + }, + { + "seqno": 107, + "headers": [ + { + "content-length": "4316" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 30 Oct 2013 13:08:38 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 27 Sep 2012 22:19:28 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31191442" + }, + { + "date": "Sat, 03 Nov 2012 12:51:16 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "Zx9+0hICgorbmj40+TVQqx/6DWk0JFijw5sOouOK4x8=" + } + ] + }, + { + "seqno": 108, + "headers": [ + { + "content-length": "82" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 27 Aug 2013 03:46:37 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:02:59 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25628121" + }, + { + "date": "Sat, 03 Nov 2012 12:51:16 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "y9gp03qLmGwdrjrggsFyxKUnduRuH6ZkhHy3J217wnA=" + } + ] + }, + { + "seqno": 109, + "headers": [ + { + "content-length": "281" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 27 Aug 2013 03:46:43 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 12 Apr 2012 03:03:15 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=25628127" + }, + { + "date": "Sat, 03 Nov 2012 12:51:16 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "y31IzOtXz6QEqDb4Yh8nL9E7Jz3QdrtFTVTfJpFI67s=" + } + ] + }, + { + "seqno": 110, + "headers": [ + { + "content-length": "18581" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 03:07:15 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:07:48 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31068960" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "cdKo7nf6SbFgEUsu8p8ZpYkyd14IkSsYwu8pEpjIPW8=" + } + ] + }, + { + "seqno": 111, + "headers": [ + { + "content-length": "686" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 02:40:01 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sun, 28 Oct 2012 21:28:22 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31067324" + }, + { + "date": "Sat, 03 Nov 2012 12:51:17 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "text/css; charset=utf-8" + }, + { + "x-fb-debug": "Mcoj0fymAm3BWRvLoE9uVgrJkXk8Wldn9hUKly6PE60=" + } + ] + }, + { + "seqno": 112, + "headers": [ + { + "content-length": "70824" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 29 Oct 2013 16:43:30 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Sun, 28 Oct 2012 14:35:10 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31117935" + }, + { + "date": "Sat, 03 Nov 2012 12:51:15 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "image/png" + }, + { + "x-fb-debug": "U6CnJQe7lFM5/wvYBRcEyvixo284qs3dxFI4vIJ3Sfo=" + } + ] + }, + { + "seqno": 113, + "headers": [ + { + "content-length": "6953" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 06 Nov 2012 13:10:12 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Mon, 29 Oct 2012 18:56:50 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=260332" + }, + { + "date": "Sat, 03 Nov 2012 12:51:20 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-shockwave-flash" + }, + { + "x-fb-debug": "8ROXKJ/K5IoNZG3RcJoN8LoohKyoDW2iTe6nY9hRINI=" + } + ] + }, + { + "seqno": 114, + "headers": [ + { + "content-length": "6953" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Tue, 06 Nov 2012 13:10:12 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Mon, 29 Oct 2012 18:56:50 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=260331" + }, + { + "date": "Sat, 03 Nov 2012 12:51:21 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-shockwave-flash" + }, + { + "x-fb-debug": "8ROXKJ/K5IoNZG3RcJoN8LoohKyoDW2iTe6nY9hRINI=" + } + ] + }, + { + "seqno": 115, + "headers": [ + { + "content-length": "15685" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Thu, 31 Oct 2013 19:03:10 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Tue, 30 Oct 2012 17:45:29 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=31299110" + }, + { + "date": "Sat, 03 Nov 2012 12:51:20 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "casrvtlqM38DGgUK+sC64wYFWqXchCM2wnMjgM8VC98=" + } + ] + }, + { + "seqno": 116, + "headers": [ + { + "content-length": "1591" + }, + { + "x-content-type-options": "nosniff" + }, + { + "content-encoding": "gzip" + }, + { + "expires": "Wed, 02 Oct 2013 14:15:24 GMT" + }, + { + "vary": "Accept-Encoding" + }, + { + "x-cnection": "close" + }, + { + "last-modified": "Thu, 20 Sep 2012 01:12:35 GMT" + }, + { + "connection": "keep-alive" + }, + { + ":status": "200" + }, + { + "cache-control": "public, max-age=28776235" + }, + { + "date": "Sat, 03 Nov 2012 12:51:29 GMT" + }, + { + "access-control-allow-origin": "*" + }, + { + "content-type": "application/x-javascript; charset=utf-8" + }, + { + "x-fb-debug": "E9XqLqcAPtaMWK+vlxTTyhNPMewUq9nSCKax+m9KMwk=" + } + ] + } + ] +} \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties index c8c72f381ed..3d1e404e15a 100644 --- a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties @@ -1,3 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.http2.LEVEL=DEBUG +org.eclipse.jetty.http2.LEVEL=INFO diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java index b20047f40f9..931736e6fe5 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java @@ -92,9 +92,9 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E> /* ------------------------------------------------------------ */ /** - * @return the next index to be used + * @return the next slot to be used */ - public int getNextIndexUnsafe() + public int getNextSlotUnsafe() { return _nextSlot; } From d4e7c0a2799f4881d0e3b062b273e0db55cbab05 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 17 Jul 2014 07:49:47 +1000 Subject: [PATCH 143/269] update encoding strategy for no ref-set --- .../org/eclipse/jetty/http/DateParser.java | 2 +- .../jetty/http2/hpack/HpackEncoder.java | 78 +++++++++++-------- .../jetty/http2/hpack/HpackPerfTest.java | 8 +- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java index 1ede4cec180..1999f17ff02 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java @@ -27,7 +27,7 @@ import java.util.TimeZone; * ThreadLocal data parsers for HTTP style dates * */ -class DateParser +public class DateParser { private static final TimeZone __GMT = TimeZone.getTimeZone("GMT"); static diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index df7d7f98beb..ee2ca7e653f 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -27,7 +27,6 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; -import org.eclipse.jetty.http2.hpack.HpackContext.StaticEntry; import org.eclipse.jetty.io.ByteBufferPool.Lease; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; @@ -40,9 +39,6 @@ public class HpackEncoder private final static HttpField[] __status= new HttpField[599]; - private final static EnumSet<HttpHeader> __NEVER_INDEX = - EnumSet.of(HttpHeader.SET_COOKIE, - HttpHeader.SET_COOKIE2); private final static EnumSet<HttpHeader> __DO_NOT_HUFFMAN = EnumSet.of(HttpHeader.COOKIE, @@ -53,22 +49,33 @@ public class HpackEncoder HttpHeader.PROXY_AUTHENTICATE, HttpHeader.PROXY_AUTHORIZATION); - private final static EnumSet<HttpHeader> __USE_REFERENCE_SET = - EnumSet.of(HttpHeader.ACCEPT, - HttpHeader.ACCEPT_CHARSET, - HttpHeader.ACCEPT_ENCODING, - HttpHeader.ACCEPT_LANGUAGE, - HttpHeader.ACCEPT_RANGES, - HttpHeader.ALLOW, - HttpHeader.AUTHORIZATION, - HttpHeader.CACHE_CONTROL, - HttpHeader.CONTENT_LANGUAGE, - HttpHeader.COOKIE, + private final static EnumSet<HttpHeader> __DO_NOT_INDEX = + EnumSet.of( + HttpHeader.CONTENT_MD5, + HttpHeader.CONTENT_RANGE, + HttpHeader.ETAG, + HttpHeader.IF_MODIFIED_SINCE, + HttpHeader.IF_UNMODIFIED_SINCE, + HttpHeader.IF_NONE_MATCH, + HttpHeader.IF_RANGE, + HttpHeader.IF_MATCH, + HttpHeader.RANGE, + HttpHeader.EXPIRES, + HttpHeader.LAST_MODIFIED, + HttpHeader.SET_COOKIE, + HttpHeader.SET_COOKIE2); + + + private final static EnumSet<HttpHeader> __NEVER_INDEX = + EnumSet.of(HttpHeader.SET_COOKIE, + HttpHeader.SET_COOKIE2); + + private final static EnumSet<HttpHeader> __DATE_HEADER = + EnumSet.of(HttpHeader.IF_MODIFIED_SINCE, HttpHeader.DATE, - HttpHeader.HOST, - HttpHeader.SERVER, - HttpHeader.SERVLET_ENGINE, - HttpHeader.USER_AGENT); + HttpHeader.EXPIRES, + HttpHeader.LAST_MODIFIED, + HttpHeader.IF_UNMODIFIED_SINCE); static { @@ -218,33 +225,37 @@ public class HpackEncoder HttpHeader header = field.getHeader(); final boolean never_index; final boolean huffman; - final boolean reference; + final boolean indexed; + final boolean date; final int name_bits; final byte mask; if (header==null) { never_index=false; huffman=true; - reference=true; + indexed=true; + date=false; name_bits = 6; mask=(byte)0x40; } - else if (__USE_REFERENCE_SET.contains(header)) + else if (__DO_NOT_INDEX.contains(header)) { - reference=true; - never_index=false; - huffman=!__DO_NOT_HUFFMAN.contains(header); - name_bits = 6; - mask=(byte)0x40; - } - else - { - reference=false; + indexed=false; never_index=__NEVER_INDEX.contains(header); + date=__DATE_HEADER.contains(header); huffman=!__DO_NOT_HUFFMAN.contains(header); name_bits = 4; mask=never_index?(byte)0x01:(byte)0x00; } + else + { + indexed=true; + never_index=false; + huffman=!__DO_NOT_HUFFMAN.contains(header); + date=__DATE_HEADER.contains(header); + name_bits = 6; + mask=(byte)0x40; + } // Add the mask bits buffer.put(mask); @@ -257,7 +268,7 @@ public class HpackEncoder encoding="Lit"+ ((name_entry==null)?"HuffName":"IdxName")+ (huffman?"HuffVal":"LitVal")+ - (reference?"Idxd":(never_index?"NeverIdx":"")); + (indexed?"Idxd":(never_index?"NeverIdx":"")); } if (name_entry!=null) @@ -272,6 +283,7 @@ public class HpackEncoder // Add the literal value String value=field.getValue(); + if (huffman) { // huffman literal value @@ -295,7 +307,7 @@ public class HpackEncoder // If we want the field referenced, then we add it to our // table and reference set. - if (reference) + if (indexed) _context.add(field); } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java index e910ef98642..c7bffc8b688 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java @@ -38,7 +38,7 @@ import org.junit.Test; public class HpackPerfTest { - int _maxHeaderTableSize=16*1024; + int _maxHeaderTableSize=4*1024; int _unencodedSize; int _encodedSize; @@ -51,8 +51,9 @@ public class HpackPerfTest @After public void after() - { - System.err.printf("headertable=%d unencoded=%d encoded=%d%n",_maxHeaderTableSize,_unencodedSize,_encodedSize); + { + System.err.printf("headertable=%d unencoded=%d encoded=%d p=%d%%%n",_maxHeaderTableSize,_unencodedSize,_encodedSize,(100*_encodedSize+49)/_unencodedSize); + } @Test @@ -127,6 +128,7 @@ public class HpackPerfTest } } } + } From a639359a7bcb0c72587435e014fc08ef7de9b695 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 18 Jul 2014 17:23:44 +1000 Subject: [PATCH 144/269] do not index content-length --- .../jetty/http2/hpack/HpackEncoder.java | 30 +++++++++---------- .../test/resources/jetty-logging.properties | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index ee2ca7e653f..9420dbb0934 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -69,14 +69,7 @@ public class HpackEncoder private final static EnumSet<HttpHeader> __NEVER_INDEX = EnumSet.of(HttpHeader.SET_COOKIE, HttpHeader.SET_COOKIE2); - - private final static EnumSet<HttpHeader> __DATE_HEADER = - EnumSet.of(HttpHeader.IF_MODIFIED_SINCE, - HttpHeader.DATE, - HttpHeader.EXPIRES, - HttpHeader.LAST_MODIFIED, - HttpHeader.IF_UNMODIFIED_SINCE); - + static { for (HttpStatus.Code code : HttpStatus.Code.values()) @@ -182,6 +175,7 @@ public class HpackEncoder private void encode(ByteBuffer buffer, HttpField field) { final int p=LOG.isDebugEnabled()?buffer.position():-1; + String encoding=null; // TODO currently we do not check if there is enough space, so we will always @@ -207,10 +201,10 @@ public class HpackEncoder } else { - encoding="IdxField"; - // So we can emit the index and add the entry to the reference Set int index=_context.index(entry); + if (p>=0) + encoding="IdxField"+(1+NBitInteger.octectsNeeded(7,index)); buffer.put((byte)0x80); NBitInteger.encode(buffer,7,index); } @@ -226,7 +220,6 @@ public class HpackEncoder final boolean never_index; final boolean huffman; final boolean indexed; - final boolean date; final int name_bits; final byte mask; if (header==null) @@ -234,7 +227,6 @@ public class HpackEncoder never_index=false; huffman=true; indexed=true; - date=false; name_bits = 6; mask=(byte)0x40; } @@ -242,17 +234,23 @@ public class HpackEncoder { indexed=false; never_index=__NEVER_INDEX.contains(header); - date=__DATE_HEADER.contains(header); huffman=!__DO_NOT_HUFFMAN.contains(header); name_bits = 4; mask=never_index?(byte)0x01:(byte)0x00; } + else if (header==HttpHeader.CONTENT_LENGTH && field.getValue().length()>1) + { + indexed=false; + never_index=false; + huffman=true; + name_bits = 4; + mask=(byte)0x00; + } else { indexed=true; never_index=false; huffman=!__DO_NOT_HUFFMAN.contains(header); - date=__DATE_HEADER.contains(header); name_bits = 6; mask=(byte)0x40; } @@ -266,7 +264,7 @@ public class HpackEncoder if (p>=0) { encoding="Lit"+ - ((name_entry==null)?"HuffName":"IdxName")+ + ((name_entry==null)?"HuffName":("IdxName"+(_context.index(name_entry)<64?'1':'X')))+ (huffman?"HuffVal":"LitVal")+ (indexed?"Idxd":(never_index?"NeverIdx":"")); } @@ -316,6 +314,6 @@ public class HpackEncoder int e=buffer.position(); if (LOG.isDebugEnabled()) LOG.debug("encoded '{}' by {} to '{}'",field,encoding,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); - } + } } } diff --git a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties index 3d1e404e15a..d33a7c32778 100644 --- a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties @@ -1,3 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog org.eclipse.jetty.http2.LEVEL=INFO - +org.eclipse.jetty.http2.hpack.LEVEL=DEBUG From 7f62f2600b943b9aed0e4771891939bf61372c5a Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Sun, 20 Jul 2014 10:23:47 +1000 Subject: [PATCH 145/269] refactored URI handling --- .../fcgi/server/HttpChannelOverFCGI.java | 4 +- .../org/eclipse/jetty/http/FinalMetaData.java | 14 +- .../org/eclipse/jetty/http/HttpParser.java | 44 +- .../org/eclipse/jetty/http/HttpTester.java | 2 +- .../java/org/eclipse/jetty/http/HttpURI.java | 322 +++----------- .../java/org/eclipse/jetty/http/MetaData.java | 2 +- .../eclipse/jetty/http/HttpParserTest.java | 2 +- .../org/eclipse/jetty/http/HttpURITest.java | 265 +++++++++++- .../jetty/http2/hpack/HpackEncoder.java | 2 +- .../jetty/http2/hpack/MetaDataBuilder.java | 8 +- .../jetty/http2/hpack/HpackDecoderTest.java | 12 +- .../rewrite/handler/RewriteRegexRuleTest.java | 2 +- .../org/eclipse/jetty/server/HttpChannel.java | 4 +- .../jetty/server/HttpChannelOverHttp.java | 14 +- .../org/eclipse/jetty/server/Request.java | 27 +- .../jetty/server/ExtendedServerTest.java | 3 +- .../org/eclipse/jetty/server/HttpURITest.java | 402 ------------------ .../org/eclipse/jetty/server/RequestTest.java | 5 +- .../AsyncContextDispatchWithQueryStrings.java | 123 +++--- .../jetty/servlet/DefaultServletTest.java | 8 - .../spdy/server/http/HttpChannelOverSPDY.java | 4 +- .../server/proxy/ProxyHTTPSPDYConnection.java | 3 +- .../java/org/eclipse/jetty/util/TypeUtil.java | 13 + .../java/org/eclipse/jetty/util/URIUtil.java | 264 +++++++----- .../org/eclipse/jetty/util/UrlEncoded.java | 53 ++- .../eclipse/jetty/util/Utf8Appendable.java | 52 +++ .../org/eclipse/jetty/util/URIUtilTest.java | 9 +- .../eclipse/jetty/util/URLEncodedTest.java | 12 +- .../jetty/util/UrlEncodedUtf8Test.java | 26 +- .../client/ClientUpgradeRequest.java | 3 +- 30 files changed, 712 insertions(+), 992 deletions(-) delete mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java index 460ee6855a3..df7afda8482 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java @@ -28,6 +28,7 @@ import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -88,7 +89,8 @@ public class HttpChannelOverFCGI extends HttpChannel String uri = path; if (query != null && query.length() > 0) uri += "?" + query; - onRequest(new FinalMetaData.Request(HttpVersion.fromString(version), method, new HttpURI(uri), fields, hostPort)); + // TODO https? + onRequest(new FinalMetaData.Request(HttpVersion.fromString(version), HttpScheme.HTTP.asString(), method, uri, fields, hostPort)); } private HttpField convertHeader(HttpField field) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java index 8aae76c5bab..e3a2bac20f2 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java @@ -51,22 +51,19 @@ public class FinalMetaData extends AbstractMetaData private final HttpVersion _version; private final HttpFields _fields; private final String _method; - private final HttpURI _uri; + private final String _uri; private final HostPortHttpField _hostPort; private final HttpScheme _scheme; - public Request(HttpVersion version, String method, HttpURI uri, HttpFields fields, HostPortHttpField hostPort) + public Request(HttpVersion version, String scheme, String method, String uri, HttpFields fields, HostPortHttpField hostPort) { _fields=fields; _version=version; _method=method; _uri=uri; _hostPort = hostPort; - String scheme = uri.getScheme(); if (scheme == null) - { _scheme = HttpScheme.HTTP; - } else { HttpScheme s = HttpScheme.CACHE.get(scheme); @@ -75,11 +72,6 @@ public class FinalMetaData extends AbstractMetaData } public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, String path, HttpFields fields) - { - this(version,scheme,method,authority,new HttpURI(path),fields); - } - - public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, HttpURI path, HttpFields fields) { _fields=fields; _version=version; @@ -126,7 +118,7 @@ public class FinalMetaData extends AbstractMetaData } @Override - public HttpURI getURI() + public String getURI() { return _uri; } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index f01ab8e2aab..a53ae22e3e4 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -142,8 +143,7 @@ public class HttpParser private HttpMethod _method; private String _methodString; private HttpVersion _version; - private ByteBuffer _uri=ByteBuffer.allocate(INITIAL_URI_LENGTH); // Tune? - private HttpURI _httpURI=new HttpURI(StandardCharsets.UTF_8); + private Utf8StringBuilder _uri=new Utf8StringBuilder(INITIAL_URI_LENGTH); // Tune? private EndOfContent _endOfContent; private long _contentLength; private long _contentPosition; @@ -523,7 +523,7 @@ public class HttpParser } else { - _uri.clear(); + _uri.reset(); setState(State.URI); // quick scan for space or EoBuffer if (buffer.hasArray()) @@ -543,18 +543,11 @@ public class HttpParser LOG.warn("URI is too large >"+_maxHeaderBytes); throw new BadMessageException(HttpStatus.REQUEST_URI_TOO_LONG_414); } - if (_uri.remaining()<=len) - { - ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()+2*len); - _uri.flip(); - uri.put(_uri); - _uri=uri; - } - _uri.put(array,p-1,len+1); + _uri.append(array,p-1,len+1); buffer.position(i-buffer.arrayOffset()); } else - _uri.put(ch); + _uri.append(ch); } } else if (ch < HttpTokens.SPACE) @@ -591,19 +584,11 @@ public class HttpParser else if (ch < HttpTokens.SPACE && ch>=0) { // HTTP/0.9 - _uri.flip(); throw new BadMessageException("HTTP/0.9 not supported"); } else { - if (!_uri.hasRemaining()) - { - ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()*2); - _uri.flip(); - uri.put(_uri); - _uri=uri; - } - _uri.put(ch); + _uri.append(ch); } break; @@ -634,8 +619,7 @@ public class HttpParser if (!(_requestHandler instanceof ProxyHandler)) throw new BadMessageException(); - _uri.flip(); - String protocol=BufferUtil.toString(_uri); + String protocol=_uri.toString(); // This is the proxy protocol, so we can assume entire first line is in buffer else 400 buffer.position(buffer.position()-1); String sAddr = getProxyField(buffer); @@ -682,7 +666,6 @@ public class HttpParser else { // HTTP/0.9 - _uri.flip(); throw new BadMessageException("HTTP/0.9 not supported"); } } @@ -709,14 +692,8 @@ public class HttpParser } setState(State.HEADER); - _uri.flip(); - if (_method == HttpMethod.CONNECT) - _httpURI.parseConnect(_uri.array(),_uri.arrayOffset()+_uri.position(),_uri.remaining()); - else - _httpURI.parse(_uri.array(),_uri.arrayOffset()+_uri.position(),_uri.remaining()); - - handle=_requestHandler.startRequest(_methodString,_httpURI, _version)||handle; + handle=_requestHandler.startRequest(_methodString,_uri.toString(), _version)||handle; continue; } else if (ch>=HttpTokens.SPACE) @@ -1185,7 +1162,7 @@ public class HttpParser if (_headerBytes>_maxHeaderBytes) { // Don't want to waste time reading data of a closed request - throw new IllegalStateException("too much data after closed"); + throw new IllegalStateException("too much data when seeking close"); } } } @@ -1491,7 +1468,6 @@ public class HttpParser _contentChunk=null; _headerBytes=0; _host=false; - _httpURI.clear(); } /* ------------------------------------------------------------------------------- */ @@ -1572,7 +1548,7 @@ public class HttpParser * @param version * @return true if handling parsing should return. */ - public boolean startRequest(String method, HttpURI uri, HttpVersion version); + public boolean startRequest(String method, String uri, HttpVersion version); } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java index 54a99779463..5ecf7b84498 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java @@ -255,7 +255,7 @@ public class HttpTester private String _uri; @Override - public boolean startRequest(String method, HttpURI uri, HttpVersion version) + public boolean startRequest(String method, String uri, HttpVersion version) { _method=method; _uri=uri.toString(); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index 0c264da2b74..fc7cdb7d61d 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -24,11 +24,9 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.UrlEncoded; -import org.eclipse.jetty.util.Utf8StringBuilder; /* ------------------------------------------------------------ */ @@ -45,11 +43,13 @@ import org.eclipse.jetty.util.Utf8StringBuilder; * <li>{@link #getQuery()} - query</li> * <li>{@link #getFragment()} - fragment</li> * </ul> - * + * + * <p>Any parameters will be returned from {@link #getPath()}, but are excluded from the + * return value of {@link #getDecodedPath()}. If there are multiple parameters, the + * {@link #getParam()} method returns only the last one. */ public class HttpURI { - private static final byte[] __empty={}; private final static int START=0, AUTH_OR_PATH=1, @@ -62,10 +62,8 @@ public class HttpURI QUERY=9, ASTERISK=10; - final Charset _charset; boolean _partial=false; - byte[] _raw=__empty; - String _rawString; + String _uri; int _scheme; int _authority; int _host; @@ -80,12 +78,6 @@ public class HttpURI public HttpURI() { - _charset = URIUtil.__CHARSET; - } - - public HttpURI(Charset charset) - { - _charset = charset; } /* ------------------------------------------------------------ */ @@ -95,55 +87,29 @@ public class HttpURI public HttpURI(boolean parsePartialAuth) { _partial=parsePartialAuth; - _charset = URIUtil.__CHARSET; } - public HttpURI(String raw) + public HttpURI(String uri) { - _rawString=raw; - byte[] b = raw.getBytes(StandardCharsets.UTF_8); - parse(b,0,b.length); - _charset = URIUtil.__CHARSET; - } - - public HttpURI(byte[] raw,int offset, int length) - { - parse2(raw,offset,length); - _charset = URIUtil.__CHARSET; + _uri=uri; + parse(uri); } public HttpURI(URI uri) { - parse(uri.toASCIIString()); - _charset = URIUtil.__CHARSET; - } - - public void parse(String raw) - { - byte[] b = StringUtil.getUtf8Bytes(raw); - parse2(b,0,b.length); - _rawString=raw; - } - - public void parseConnect(String raw) - { - byte[] b = StringUtil.getBytes(raw); - parseConnect(b,0,b.length); - _rawString=raw; - } - - public void parse(byte[] raw,int offset, int length) - { - _rawString=null; - parse2(raw,offset,length); + this(uri.toASCIIString()); } - public void parseConnect(byte[] raw,int offset, int length) + public void parseConnect(String authority) { - _rawString=null; + parseConnect(authority,0,authority.length()); + } + + public void parseConnect(String authority,int offset,int length) + { + _uri=authority; _encoded=false; - _raw=raw; int i=offset; int e=offset+length; int state=AUTH; @@ -160,7 +126,7 @@ public class HttpURI loop: while (i<e) { - char c=(char)(0xff&_raw[i]); + char c=authority.charAt(i); int s=i++; switch (state) @@ -189,7 +155,7 @@ public class HttpURI { case '/': { - throw new IllegalArgumentException("No closing ']' for " + new String(_raw,offset,length,_charset)); + throw new IllegalArgumentException("No closing ']' for " + _uri.substring(offset,length)); } case ']': { @@ -204,34 +170,34 @@ public class HttpURI } if (_port<_path) - _portValue=TypeUtil.parseInt(_raw, _port+1, _path-_port-1,10); + _portValue=TypeUtil.parseInt(_uri, _port+1, _path-_port-1,10); else throw new IllegalArgumentException("No port"); _path=offset; } - private void parse2(byte[] raw,int offset, int length) + public void parse(String uri) { + _uri=uri; _encoded=false; - _raw=raw; - int i=offset; - int e=offset+length; + int i=0; + int e=uri.length(); int state=START; - int m=offset; - _end=offset+length; - _scheme=offset; - _authority=offset; - _host=offset; - _port=offset; + int m=i; + _end=e; + _scheme=i; + _authority=i; + _host=i; + _port=i; _portValue=-1; - _path=offset; + _path=i; _param=_end; _query=_end; _fragment=_end; while (i<e) { - char c=(char)(0xff&_raw[i]); + char c=uri.charAt(i); int s=i++; state: switch (state) @@ -295,29 +261,6 @@ public class HttpURI case SCHEME_OR_PATH: { - // short cut for http and https - if (length>6 && c=='t') - { - if (_raw[offset+3]==':') - { - s=offset+3; - i=offset+4; - c=':'; - } - else if (_raw[offset+4]==':') - { - s=offset+4; - i=offset+5; - c=':'; - } - else if (_raw[offset+5]==':') - { - s=offset+5; - i=offset+6; - c=':'; - } - } - switch (c) { case ':': @@ -325,7 +268,7 @@ public class HttpURI m = i++; _authority = m; _path = m; - c = (char)(0xff & _raw[i]); + c = uri.charAt(i); if (c == '/') state = AUTH_OR_PATH; else @@ -365,6 +308,8 @@ public class HttpURI _fragment = s; break; } + + } continue; } @@ -408,7 +353,7 @@ public class HttpURI { case '/': { - throw new IllegalArgumentException("No closing ']' for " + new String(_raw,offset,length,_charset)); + throw new IllegalArgumentException("No closing ']' for ipv6 in " + uri); } case ']': { @@ -481,6 +426,11 @@ public class HttpURI _fragment = s; break state; } + case '/': + { + state=PATH; + break state; + } } continue; } @@ -503,7 +453,7 @@ public class HttpURI } if (_port<_path) - _portValue=TypeUtil.parseInt(_raw, _port+1, _path-_port-1,10); + _portValue=TypeUtil.parseInt(_uri, _port+1, _path-_port-1,10); } public String getScheme() @@ -511,35 +461,26 @@ public class HttpURI if (_scheme==_authority) return null; int l=_authority-_scheme; - if (l==5 && - _raw[_scheme]=='h' && - _raw[_scheme+1]=='t' && - _raw[_scheme+2]=='t' && - _raw[_scheme+3]=='p' ) + if (l==5 && _uri.startsWith("http:")) return HttpScheme.HTTP.asString(); - if (l==6 && - _raw[_scheme]=='h' && - _raw[_scheme+1]=='t' && - _raw[_scheme+2]=='t' && - _raw[_scheme+3]=='p' && - _raw[_scheme+4]=='s' ) + if (l==6 && _uri.startsWith("https:")) return HttpScheme.HTTPS.asString(); - return new String(_raw,_scheme,_authority-_scheme-1,_charset); + return _uri.substring(_scheme,_authority-_scheme-1); } public String getAuthority() { if (_authority==_path) return null; - return new String(_raw,_authority,_path-_authority,_charset); + return _uri.substring(_authority,_path); } public String getHost() { if (_host==_port) return null; - return new String(_raw,_host,_port-_host,_charset); + return _uri.substring(_host,_port); } public int getPort() @@ -549,169 +490,44 @@ public class HttpURI public String getPath() { - if (_path==_param) + if (_path==_query) return null; - return new String(_raw,_path,_param-_path,_charset); + return _uri.substring(_path,_query); } public String getDecodedPath() { - if (_path==_param) + if (_path==_query) return null; - - Utf8StringBuilder utf8b=null; - - for (int i=_path;i<_param;i++) - { - byte b = _raw[i]; - - if (b=='%') - { - if (utf8b==null) - { - utf8b=new Utf8StringBuilder(); - utf8b.append(_raw,_path,i-_path); - } - - if ((i+2)>=_param) - throw new IllegalArgumentException("Bad % encoding: "+this); - if (_raw[i+1]=='u') - { - if ((i+5)>=_param) - throw new IllegalArgumentException("Bad %u encoding: "+this); - try - { - String unicode = new String(Character.toChars(TypeUtil.parseInt(_raw,i+2,4,16))); - utf8b.getStringBuilder().append(unicode); - i+=5; - } - catch(Exception e) - { - throw new RuntimeException(e); - } - } - else - { - b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16)); - utf8b.append(b); - i+=2; - } - continue; - } - else if (utf8b!=null) - { - utf8b.append(b); - } - } - - if (utf8b==null) - return StringUtil.toUTF8String(_raw, _path, _param-_path); - return utf8b.toString(); - } - - public String getDecodedPath(String encoding) - { - return getDecodedPath(Charset.forName(encoding)); - } - - public String getDecodedPath(Charset encoding) - { - if (_path==_param) - return null; - - int length = _param-_path; - byte[] bytes=null; - int n=0; - - for (int i=_path;i<_param;i++) - { - byte b = _raw[i]; - - if (b=='%') - { - if (bytes==null) - { - bytes=new byte[length]; - System.arraycopy(_raw,_path,bytes,0,n); - } - - if ((i+2)>=_param) - throw new IllegalArgumentException("Bad % encoding: "+this); - if (_raw[i+1]=='u') - { - if ((i+5)>=_param) - throw new IllegalArgumentException("Bad %u encoding: "+this); - - try - { - String unicode = new String(Character.toChars(TypeUtil.parseInt(_raw,i+2,4,16))); - byte[] encoded = unicode.getBytes(encoding); - System.arraycopy(encoded,0,bytes,n,encoded.length); - n+=encoded.length; - i+=5; - } - catch(Exception e) - { - throw new RuntimeException(e); - } - } - else - { - b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16)); - bytes[n++]=b; - i+=2; - } - continue; - } - else if (bytes==null) - { - n++; - continue; - } - - bytes[n++]=b; - } - - - if (bytes==null) - return new String(_raw,_path,_param-_path,encoding); - - return new String(bytes,0,n,encoding); + return URIUtil.decodePath(_uri,_path,_query-_path); } public String getPathAndParam() { if (_path==_query) return null; - return new String(_raw,_path,_query-_path,_charset); + return _uri.substring(_path,_query); } public String getCompletePath() { if (_path==_end) return null; - return new String(_raw,_path,_end-_path,_charset); + return _uri.substring(_path,_end); } public String getParam() { if (_param==_query) return null; - return new String(_raw,_param+1,_query-_param-1,_charset); + return _uri.substring(_param+1,_query); } public String getQuery() { if (_query==_fragment) return null; - return new String(_raw,_query+1,_fragment-_query-1,_charset); - } - - public String getQuery(String encoding) - { - if (_query==_fragment) - return null; - return StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding); + return _uri.substring(_query+1,_fragment); } public boolean hasQuery() @@ -723,28 +539,22 @@ public class HttpURI { if (_fragment==_end) return null; - return new String(_raw,_fragment+1,_end-_fragment-1,_charset); + + return _uri.substring(_fragment+1,_end); } public void decodeQueryTo(MultiMap<String> parameters) { if (_query==_fragment) return; - if (_charset.equals(StandardCharsets.UTF_8)) - UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters); - else - UrlEncoded.decodeTo(new String(_raw,_query+1,_fragment-_query-1,_charset),parameters,_charset,-1); + UrlEncoded.decodeUtf8To(_uri,_query+1,_fragment-_query-1,parameters); } public void decodeQueryTo(MultiMap<String> parameters, String encoding) throws UnsupportedEncodingException { if (_query==_fragment) return; - - if (encoding==null || StringUtil.isUTF8(encoding)) - UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters); - else - UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding,-1); + decodeQueryTo(parameters,Charset.forName(encoding)); } public void decodeQueryTo(MultiMap<String> parameters, Charset encoding) throws UnsupportedEncodingException @@ -753,25 +563,22 @@ public class HttpURI return; if (encoding==null || StandardCharsets.UTF_8.equals(encoding)) - UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters); + UrlEncoded.decodeUtf8To(_uri,_query+1,_fragment-_query-1,parameters); else - UrlEncoded.decodeTo(new String(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding,-1); + UrlEncoded.decodeTo(_uri.substring(_query+1,_fragment-_query-1),parameters,encoding); } public void clear() { _scheme=_authority=_host=_port=_path=_param=_query=_fragment=_end=0; - _raw=__empty; - _rawString=""; + _uri=null; _encoded=false; } @Override public String toString() { - if (_rawString==null) - _rawString=new String(_raw,_scheme,_end-_scheme,_charset); - return _rawString; + return _uri; } public boolean equals(Object o) @@ -782,10 +589,5 @@ public class HttpURI return false; return toString().equals(o.toString()); } - - public void writeTo(Utf8StringBuilder buf) - { - buf.append(_raw,_scheme,_end-_scheme); - } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index bfe4bb4f0fe..4bf47ab3793 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -34,7 +34,7 @@ public interface MetaData extends Iterable<HttpField> public HttpScheme getScheme(); public String getHost(); public int getPort(); - public HttpURI getURI(); + public String getURI(); } /* -------------------------------------------------------- */ diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 3b328f554f2..78751a97714 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -1561,7 +1561,7 @@ public class HttpParserTest } @Override - public boolean startRequest(String method, HttpURI uri, HttpVersion version) + public boolean startRequest(String method, String uri, HttpVersion version) { _fields.clear(); _headers= -1; diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java index fd5023a56c0..b5502fd9f96 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java @@ -20,9 +20,19 @@ package org.eclipse.jetty.http; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import java.io.UnsupportedEncodingException; import java.net.URI; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import org.eclipse.jetty.util.MultiMap; +import org.eclipse.jetty.util.Utf8Appendable; +import org.junit.Assert; import org.junit.Test; @@ -32,10 +42,10 @@ public class HttpURITest String[][] tests= { {"/path/to/context",null,null,"-1","/path/to/context",null,null,null}, - {"http://example.com/path/to/context;param?query=%22value%22#fragment","http","example.com","-1","/path/to/context","param","query=%22value%22","fragment"}, - {"http://[::1]/path/to/context;param?query=%22value%22#fragment","http","[::1]","-1","/path/to/context","param","query=%22value%22","fragment"}, - {"http://example.com:8080/path/to/context;param?query=%22value%22#fragment","http","example.com","8080","/path/to/context","param","query=%22value%22","fragment"}, - {"http://[::1]:8080/path/to/context;param?query=%22value%22#fragment","http","[::1]","8080","/path/to/context","param","query=%22value%22","fragment"}, + {"http://example.com/path/to/context;param?query=%22value%22#fragment","http","example.com","-1","/path/to/context;param","param","query=%22value%22","fragment"}, + {"http://[::1]/path/to/context;param?query=%22value%22#fragment","http","[::1]","-1","/path/to/context;param","param","query=%22value%22","fragment"}, + {"http://example.com:8080/path/to/context;param?query=%22value%22#fragment","http","example.com","8080","/path/to/context;param","param","query=%22value%22","fragment"}, + {"http://[::1]:8080/path/to/context;param?query=%22value%22#fragment","http","[::1]","8080","/path/to/context;param","param","query=%22value%22","fragment"}, }; public static int @@ -76,4 +86,251 @@ public class HttpURITest assertEquals(test[FRAGMENT], uri.getFragment()); } } + + private final String[][] partial_tests= + { + /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, + /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, + /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, + /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, + /* 4*/ {"/path/info;param",null,null,null,null,"/path/info;param","param",null,null}, + /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info;param","param",null,"fragment"}, + /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info;param","param","query",null}, + /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info;param","param","query","fragment"}, + /* 8*/ {"//host/path/info",null,"//host","host",null,"/path/info",null,null,null}, + /* 9*/ {"//user@host/path/info",null,"//user@host","host",null,"/path/info",null,null,null}, + /*10*/ {"//user@host:8080/path/info",null,"//user@host:8080","host","8080","/path/info",null,null,null}, + /*11*/ {"//host:8080/path/info",null,"//host:8080","host","8080","/path/info",null,null,null}, + /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, + /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, + /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, + /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, + /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info;param","param",null,null}, + /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info;param","param",null,"fragment"}, + /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info;param","param","query",null}, + /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info;param","param","query","fragment"}, + /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info;param","param","query","fragment"}, + /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info;param","param","query","fragment"}, + /*22*/ {"http:///;?#","http","//",null,null,"/;","","",""}, + /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, + /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, + /*25*/ {"//host:8080//",null,"//host:8080","host","8080","//",null,null,null}, + /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, + /*27*/ {"//",null,"//",null,null,null,null,null,null}, + /*28*/ {"/;param",null, null, null,null,"/;param", "param",null,null}, + /*29*/ {"/?x=y",null, null, null,null,"/", null,"x=y",null}, + /*30*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null}, + /*31*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"}, + /*32*/ {"http://localhost:8080", "http", "//localhost:8080", "localhost", "8080", null, null, null, null}, + /*33*/ {"./?foo:bar=:1:1::::",null,null,null,null,"./",null,"foo:bar=:1:1::::",null} + }; + + @Test + public void testPartialURIs() throws Exception + { + HttpURI uri = new HttpURI(true); + + for (int t=0;t<partial_tests.length;t++) + { + uri.parse(partial_tests[t][0]); + assertEquals(t+" "+partial_tests[t][0],partial_tests[t][1],uri.getScheme()); + assertEquals(t+" "+partial_tests[t][0],partial_tests[t][2],uri.getAuthority()); + assertEquals(t+" "+partial_tests[t][0],partial_tests[t][3],uri.getHost()); + assertEquals(t+" "+partial_tests[t][0],partial_tests[t][4]==null?-1:Integer.parseInt(partial_tests[t][4]),uri.getPort()); + assertEquals(t+" "+partial_tests[t][0],partial_tests[t][5],uri.getPath()); + assertEquals(t+" "+partial_tests[t][0],partial_tests[t][6],uri.getParam()); + assertEquals(t+" "+partial_tests[t][0],partial_tests[t][7],uri.getQuery()); + assertEquals(t+" "+partial_tests[t][0],partial_tests[t][8],uri.getFragment()); + assertEquals(partial_tests[t][0], uri.toString()); + } + + } + + private final String[][] path_tests= + { + /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, + /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, + /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, + /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, + /* 4*/ {"/path/info;param",null,null,null,null,"/path/info;param","param",null,null}, + /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info;param","param",null,"fragment"}, + /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info;param","param","query",null}, + /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info;param","param","query","fragment"}, + /* 8*/ {"//host/path/info",null,null,null,null,"//host/path/info",null,null,null}, + /* 9*/ {"//user@host/path/info",null,null,null,null,"//user@host/path/info",null,null,null}, + /*10*/ {"//user@host:8080/path/info",null,null,null,null,"//user@host:8080/path/info",null,null,null}, + /*11*/ {"//host:8080/path/info",null,null,null,null,"//host:8080/path/info",null,null,null}, + /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, + /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, + /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, + /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, + /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info;param","param",null,null}, + /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info;param","param",null,"fragment"}, + /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info;param","param","query",null}, + /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info;param","param","query","fragment"}, + /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info;param","param","query","fragment"}, + /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info;param","param","query","fragment"}, + /*22*/ {"http:///;?#","http","//",null,null,"/;","","",""}, + /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, + /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, + /*25*/ {"//host:8080//",null,null,null,null,"//host:8080//",null,null,null}, + /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, + /*27*/ {"//",null,null,null,null,"//",null,null,null}, + /*28*/ {"http://localhost/","http","//localhost","localhost",null,"/",null,null,null}, + /*29*/ {"http://localhost:8080/", "http", "//localhost:8080", "localhost","8080","/", null, null,null}, + /*30*/ {"http://localhost/?x=y", "http", "//localhost", "localhost",null,"/", null,"x=y",null}, + /*31*/ {"/;param",null, null, null,null,"/;param", "param",null,null}, + /*32*/ {"/?x=y",null, null, null,null,"/", null,"x=y",null}, + /*33*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null}, + /*34*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"}, + /*35*/ {"http://192.0.0.1:8080/","http","//192.0.0.1:8080","192.0.0.1","8080","/",null,null,null}, + /*36*/ {"http://[2001:db8::1]:8080/","http","//[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, + /*37*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, + /*38*/ {"http://[2001:db8::1]/","http","//[2001:db8::1]","[2001:db8::1]",null,"/",null,null,null}, + /*39*/ {"//[2001:db8::1]:8080/",null,null,null,null,"//[2001:db8::1]:8080/",null,null,null}, + /*40*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, + /*41*/ {"*",null,null,null,null,"*",null, null,null} + }; + + @Test + public void testPathURIs() throws Exception + { + HttpURI uri = new HttpURI(); + + for (int t=0;t<path_tests.length;t++) + { + uri.parse(path_tests[t][0]); + assertEquals(t+" "+path_tests[t][0],path_tests[t][1],uri.getScheme()); + assertEquals(t+" "+path_tests[t][0],path_tests[t][2],uri.getAuthority()); + assertEquals(t+" "+path_tests[t][0],path_tests[t][3],uri.getHost()); + assertEquals(t+" "+path_tests[t][0],path_tests[t][4]==null?-1:Integer.parseInt(path_tests[t][4]),uri.getPort()); + assertEquals(t+" "+path_tests[t][0],path_tests[t][5],uri.getPath()); + assertEquals(t+" "+path_tests[t][0],path_tests[t][6],uri.getParam()); + assertEquals(t+" "+path_tests[t][0],path_tests[t][7],uri.getQuery()); + assertEquals(t+" "+path_tests[t][0],path_tests[t][8],uri.getFragment()); + assertEquals(path_tests[t][0], uri.toString()); + } + + } + + @Test + public void testInvalidAddress() throws Exception + { + assertInvalidURI("http://[ffff::1:8080/", "Invalid URL; no closing ']' -- should throw exception"); + assertInvalidURI("**", "only '*', not '**'"); + assertInvalidURI("*/", "only '*', not '*/'"); + } + + private void assertInvalidURI(String invalidURI, String message) + { + HttpURI uri = new HttpURI(); + try + { + uri.parse(invalidURI); + fail(message); + } + catch (IllegalArgumentException e) + { + assertTrue(true); + } + } + + @Test + public void testUnicodeErrors() throws UnsupportedEncodingException + { + String uri="http://server/path?invalid=data%uXXXXhere%u000"; + try + { + URLDecoder.decode(uri,"UTF-8"); + Assert.assertTrue(false); + } + catch (IllegalArgumentException e) + { + } + + HttpURI huri=new HttpURI(uri); + MultiMap<String> params = new MultiMap<>(); + huri.decodeQueryTo(params); + assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0)); + + huri=new HttpURI(uri); + params = new MultiMap<>(); + huri.decodeQueryTo(params,StandardCharsets.UTF_8); + assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0)); + + } + + @Test + public void testExtB() throws Exception + { + for (String value: new String[]{"a","abcdABCD","\u00C0","\u697C","\uD869\uDED5","\uD840\uDC08"} ) + { + HttpURI uri = new HttpURI("/path?value="+URLEncoder.encode(value,"UTF-8")); + + MultiMap<String> parameters = new MultiMap<>(); + uri.decodeQueryTo(parameters,StandardCharsets.UTF_8); + assertEquals(value,parameters.getString("value")); + } + } + + + private final String[][] connect_tests= + { + /* 0*/ {"localhost:8080","localhost","8080"}, + /* 1*/ {"127.0.0.1:8080","127.0.0.1","8080"}, + /* 2*/ {"[127::0::0::1]:8080","[127::0::0::1]","8080"}, + /* 3*/ {"error",null,null}, + /* 4*/ {"http://localhost:8080/",null,null}, + }; + + @Test + public void testCONNECT() throws Exception + { + HttpURI uri = new HttpURI(); + for (int i=0;i<connect_tests.length;i++) + { + try + { + uri.parseConnect(connect_tests[i][0]); + assertEquals("path"+i,connect_tests[i][0].trim(),uri.getPath()); + assertEquals("host"+i,connect_tests[i][1],uri.getHost()); + assertEquals("port"+i,Integer.parseInt(connect_tests[i][2]),uri.getPort()); + } + catch(Exception e) + { + assertNull("error"+i,connect_tests[i][1]); + } + } + } + + + @Test + public void testParams() throws Exception + { + HttpURI uri = new HttpURI("/foo/bar"); + assertEquals("/foo/bar",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + assertEquals(null,uri.getParam()); + + uri = new HttpURI("/foo/bar;jsessionid=12345"); + assertEquals("/foo/bar;jsessionid=12345",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + assertEquals("jsessionid=12345",uri.getParam()); + + uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345"); + assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + assertEquals("jsessionid=12345",uri.getParam()); + + uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345?name=value"); + assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + assertEquals("jsessionid=12345",uri.getParam()); + + uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345#target"); + assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + assertEquals("jsessionid=12345",uri.getParam()); + + } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 445e55370b6..78ac879f74f 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -142,7 +142,7 @@ public class HpackEncoder encode(buffer,new HttpField(":scheme",request.getScheme().asString())); encode(buffer,new HttpField(":method",request.getMethod())); encode(buffer,new HttpField(":authority",request.getPort()>0?(request.getHost()+':'+request.getPort()):request.getHost())); - encode(buffer,new HttpField(":path",request.getURI().getPath())); + encode(buffer,new HttpField(":path",request.getURI())); } else if (metadata.isResponse()) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 368401e3733..9d2bac4873e 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -42,7 +42,7 @@ public class MetaDataBuilder private String _method; private HttpScheme _scheme; private HostPortHttpField _authority; - private HttpURI _path; + private String _path; private HttpFields _fields = new HttpFields(10); @@ -91,10 +91,6 @@ public class MetaDataBuilder _scheme = (HttpScheme)value.getStaticValue(); break; - case ":path": - _path = (HttpURI)value.getStaticValue(); - break; - default: throw new IllegalArgumentException(); } @@ -120,7 +116,7 @@ public class MetaDataBuilder break; case ":path": - _path=new HttpURI(field.getValue()); + _path=field.getValue(); break; default: diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index 9fcb6ac5e9e..d3966d79012 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -53,7 +53,7 @@ public class HpackDecoderTest assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getURI().getPath()); + assertEquals("/",request.getURI()); assertEquals("www.example.com",request.getHost()); assertFalse(request.iterator().hasNext()); @@ -66,7 +66,7 @@ public class HpackDecoderTest assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getURI().getPath()); + assertEquals("/",request.getURI()); assertEquals("www.example.com",request.getHost()); Iterator<HttpField> iterator=request.iterator(); assertTrue(iterator.hasNext()); @@ -82,7 +82,7 @@ public class HpackDecoderTest assertEquals("GET",request.getMethod()); assertEquals(HttpScheme.HTTPS,request.getScheme()); - assertEquals("/index.html",request.getURI().getPath()); + assertEquals("/index.html",request.getURI()); assertEquals("www.example.com",request.getHost()); iterator=request.iterator(); assertTrue(iterator.hasNext()); @@ -103,7 +103,7 @@ public class HpackDecoderTest assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getURI().getPath()); + assertEquals("/",request.getURI()); assertEquals("www.example.com",request.getHost()); assertFalse(request.iterator().hasNext()); @@ -116,7 +116,7 @@ public class HpackDecoderTest assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getURI().getPath()); + assertEquals("/",request.getURI()); assertEquals("www.example.com",request.getHost()); Iterator<HttpField> iterator=request.iterator(); assertTrue(iterator.hasNext()); @@ -131,7 +131,7 @@ public class HpackDecoderTest assertEquals("GET",request.getMethod()); assertEquals(HttpScheme.HTTPS,request.getScheme()); - assertEquals("/index.html",request.getURI().getPath()); + assertEquals("/index.html",request.getURI()); assertEquals("www.example.com",request.getHost()); iterator=request.iterator(); assertTrue(iterator.hasNext()); diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java index f2be9ed41cb..7cf8f2ccb02 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java @@ -89,7 +89,7 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase if (test[5]!=null) { MultiMap<String> params=new MultiMap<String>(); - UrlEncoded.decodeTo(test[5],params, StandardCharsets.UTF_8,-1); + UrlEncoded.decodeTo(test[5],params, StandardCharsets.UTF_8); for (String n:params.keySet()) assertEquals(params.getString(n),_request.getParameter(n)); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index f52ade040d9..48f08753009 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -205,9 +205,6 @@ public class HttpChannel implements Runnable */ public boolean handle() { - if (LOG.isDebugEnabled()) - LOG.debug("{} handle enter", this); - final HttpChannel last = setCurrentHttpChannel(this); String threadName = null; @@ -215,6 +212,7 @@ public class HttpChannel implements Runnable { threadName = Thread.currentThread().getName(); Thread.currentThread().setName(threadName + " - " + _request.getUri()); + LOG.debug("{} handle enter", this); } HttpChannelState.Action action = _state.handling(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index cbe1883de7f..cb68aeb1f5b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -35,7 +35,6 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; @@ -50,7 +49,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl */ private final HttpConnection _httpConnection; private String _method; - private HttpURI _uri; + private String _uri; private HttpVersion _version; private final HttpFields _fields = new HttpFields(); private HostPortHttpField _hostPort; @@ -69,10 +68,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl @Override public HttpScheme getScheme() { - String scheme = _uri.getScheme(); - if (scheme==null || !scheme.endsWith("s")) - return HttpScheme.HTTP; - return HttpScheme.HTTPS; + return HttpScheme.HTTP; } @Override @@ -88,7 +84,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl } @Override - public HttpURI getURI() + public String getURI() { return _uri; } @@ -141,10 +137,10 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl } @Override - public boolean startRequest(String method, HttpURI uri, HttpVersion version) + public boolean startRequest(String method, String uri, HttpVersion version) { _method=method; - _uri=uri; + _uri=uri.toString(); _version=version; _expect = false; _expect100Continue = false; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index d6c6a4b378c..7ca5312d280 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -948,12 +948,7 @@ public class Request implements HttpServletRequest public String getQueryString() { if (_queryString == null && _uri != null) - { - if (_queryEncoding == null) - _queryString = _uri.getQuery(); - else - _queryString = _uri.getQuery(_queryEncoding); - } + _queryString = _uri.getQuery(); return _queryString; } @@ -1544,7 +1539,7 @@ public class Request implements HttpServletRequest setMethod(request.getMethod()); setScheme(request.getScheme().asString()); - HttpURI uri = request.getURI(); + HttpURI uri = new HttpURI(request.getURI()); String uriHost=uri.getHost(); if (uriHost!=null) @@ -1559,20 +1554,10 @@ public class Request implements HttpServletRequest setServerPort(request.getPort()); } - setUri(request.getURI()); + setUri(uri); - String path; - try - { - path = uri.getDecodedPath(); - } - catch (Exception e) - { - LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1"); - LOG.ignore(e); - path = uri.getDecodedPath(StandardCharsets.ISO_8859_1); - } + String path = uri.getDecodedPath(); String info = URIUtil.canonicalPath(path); // TODO should this be done prior to decoding??? @@ -2182,13 +2167,13 @@ public class Request implements HttpServletRequest { MultiMap<String> newQueryParams = new MultiMap<>(); // Have to assume ENCODING because we can't know otherwise. - UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING, -1); + UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING); MultiMap<String> oldQueryParams = _queryParameters; if (oldQueryParams == null && _queryString != null) { oldQueryParams = new MultiMap<>(); - UrlEncoded.decodeTo(_queryString, oldQueryParams, getQueryEncoding(), -1); + UrlEncoded.decodeTo(_queryString, oldQueryParams, getQueryEncoding()); } MultiMap<String> mergedQueryParams = newQueryParams; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java index 877c237bc0b..37ea80438e7 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java @@ -31,7 +31,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.SelectChannelEndPoint; @@ -105,7 +104,7 @@ public class ExtendedServerTest extends HttpServerTestBase return new HttpChannelOverHttp(this, getConnector(), getHttpConfiguration(), getEndPoint(), this, httpInput) { @Override - public boolean startRequest(String method, HttpURI uri, HttpVersion version) + public boolean startRequest(String method, String uri, HttpVersion version) { getRequest().setAttribute("DispatchedAt",((ExtendedEndPoint)getEndPoint()).getLastSelected()); return super.startRequest(method,uri,version); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java deleted file mode 100644 index 58497def1be..00000000000 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java +++ /dev/null @@ -1,402 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.Utf8Appendable; -import org.junit.Assert; -import org.junit.Test; - -public class HttpURITest -{ - private final String[][] partial_tests= - { - /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, - /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, - /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, - /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, - /* 4*/ {"/path/info;param",null,null,null,null,"/path/info","param",null,null}, - /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info","param",null,"fragment"}, - /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info","param","query",null}, - /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info","param","query","fragment"}, - /* 8*/ {"//host/path/info",null,"//host","host",null,"/path/info",null,null,null}, - /* 9*/ {"//user@host/path/info",null,"//user@host","host",null,"/path/info",null,null,null}, - /*10*/ {"//user@host:8080/path/info",null,"//user@host:8080","host","8080","/path/info",null,null,null}, - /*11*/ {"//host:8080/path/info",null,"//host:8080","host","8080","/path/info",null,null,null}, - /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, - /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, - /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, - /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, - /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info","param",null,null}, - /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info","param",null,"fragment"}, - /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info","param","query",null}, - /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info","param","query","fragment"}, - /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info","param","query","fragment"}, - /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info","param","query","fragment"}, - /*22*/ {"http:///;?#","http","//",null,null,"/","","",""}, - /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, - /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, - /*25*/ {"//host:8080//",null,"//host:8080","host","8080","//",null,null,null}, - /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, - /*27*/ {"//",null,"//",null,null,null,null,null,null}, - /*28*/ {"/;param",null, null, null,null,"/", "param",null,null}, - /*29*/ {"/?x=y",null, null, null,null,"/", null,"x=y",null}, - /*30*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null}, - /*31*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"}, - /*32*/ {"http://localhost:8080", "http", "//localhost:8080", "localhost", "8080", null, null, null, null}, - /*33*/ {"./?foo:bar=:1:1::::",null,null,null,null,"./",null,"foo:bar=:1:1::::",null} - }; - - @Test - public void testPartialURIs() throws Exception - { - HttpURI uri = new HttpURI(true); - - for (int t=0;t<partial_tests.length;t++) - { - uri.parse(partial_tests[t][0].getBytes(),0,partial_tests[t][0].length()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][1],uri.getScheme()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][2],uri.getAuthority()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][3],uri.getHost()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][4]==null?-1:Integer.parseInt(partial_tests[t][4]),uri.getPort()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][5],uri.getPath()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][6],uri.getParam()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][7],uri.getQuery()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][8],uri.getFragment()); - assertEquals(partial_tests[t][0], uri.toString()); - } - - } - - private final String[][] path_tests= - { - /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, - /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, - /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, - /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, - /* 4*/ {"/path/info;param",null,null,null,null,"/path/info","param",null,null}, - /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info","param",null,"fragment"}, - /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info","param","query",null}, - /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info","param","query","fragment"}, - /* 8*/ {"//host/path/info",null,null,null,null,"//host/path/info",null,null,null}, - /* 9*/ {"//user@host/path/info",null,null,null,null,"//user@host/path/info",null,null,null}, - /*10*/ {"//user@host:8080/path/info",null,null,null,null,"//user@host:8080/path/info",null,null,null}, - /*11*/ {"//host:8080/path/info",null,null,null,null,"//host:8080/path/info",null,null,null}, - /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, - /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, - /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, - /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, - /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info","param",null,null}, - /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info","param",null,"fragment"}, - /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info","param","query",null}, - /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info","param","query","fragment"}, - /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info","param","query","fragment"}, - /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info","param","query","fragment"}, - /*22*/ {"http:///;?#","http","//",null,null,"/","","",""}, - /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, - /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, - /*25*/ {"//host:8080//",null,null,null,null,"//host:8080//",null,null,null}, - /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, - /*27*/ {"//",null,null,null,null,"//",null,null,null}, - /*28*/ {"http://localhost/","http","//localhost","localhost",null,"/",null,null,null}, - /*29*/ {"http://localhost:8080/", "http", "//localhost:8080", "localhost","8080","/", null, null,null}, - /*30*/ {"http://localhost/?x=y", "http", "//localhost", "localhost",null,"/", null,"x=y",null}, - /*31*/ {"/;param",null, null, null,null,"/", "param",null,null}, - /*32*/ {"/?x=y",null, null, null,null,"/", null,"x=y",null}, - /*33*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null}, - /*34*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"}, - /*35*/ {"http://192.0.0.1:8080/","http","//192.0.0.1:8080","192.0.0.1","8080","/",null,null,null}, - /*36*/ {"http://[2001:db8::1]:8080/","http","//[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, - /*37*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, - /*38*/ {"http://[2001:db8::1]/","http","//[2001:db8::1]","[2001:db8::1]",null,"/",null,null,null}, - /*39*/ {"//[2001:db8::1]:8080/",null,null,null,null,"//[2001:db8::1]:8080/",null,null,null}, - /*40*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, - /*41*/ {"*",null,null,null,null,"*",null, null,null} - }; - - @Test - public void testPathURIs() throws Exception - { - HttpURI uri = new HttpURI(); - - for (int t=0;t<path_tests.length;t++) - { - uri.parse(path_tests[t][0].getBytes(),0,path_tests[t][0].length()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][1],uri.getScheme()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][2],uri.getAuthority()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][3],uri.getHost()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][4]==null?-1:Integer.parseInt(path_tests[t][4]),uri.getPort()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][5],uri.getPath()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][6],uri.getParam()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][7],uri.getQuery()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][8],uri.getFragment()); - assertEquals(path_tests[t][0], uri.toString()); - } - - } - - @Test - public void testInvalidAddress() throws Exception - { - assertInvalidURI("http://[ffff::1:8080/", "Invalid URL; no closing ']' -- should throw exception"); - assertInvalidURI("**", "only '*', not '**'"); - assertInvalidURI("*/", "only '*', not '*/'"); - } - - private void assertInvalidURI(String invalidURI, String message) - { - HttpURI uri = new HttpURI(); - try - { - uri.parse(invalidURI); - fail(message); - } - catch (IllegalArgumentException e) - { - assertTrue(true); - } - } - - private final String[][] encoding_tests= - { - /* 0*/ {"/path/info","/path/info", "UTF-8"}, - /* 1*/ {"/path/%69nfo","/path/info", "UTF-8"}, - /* 2*/ {"http://host/path/%69nfo","/path/info", "UTF-8"}, - /* 3*/ {"http://host/path/%69nf%c2%a4","/path/inf\u00a4", "UTF-8"}, - /* 4*/ {"http://host/path/%E5", "/path/\u00e5", "ISO-8859-1"}, - /* 5*/ {"/foo/%u30ED/bar%3Fabc%3D123%26xyz%3D456","/foo/\u30ed/bar?abc=123&xyz=456","UTF-8"} - }; - - @Test - public void testEncoded() - { - HttpURI uri = new HttpURI(); - - for (int t=0;t<encoding_tests.length;t++) - { - uri.parse(encoding_tests[t][0]); - assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath(encoding_tests[t][2])); - - if ("UTF-8".equalsIgnoreCase(encoding_tests[t][2])) - assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath()); - } - } - - @Test - public void testNoPercentEncodingOfQueryUsingNonUTF8() throws Exception - { - byte[] utf8_bytes = "/%D0%A1%D1%82%D1%80%D0%BE%D0%BD%D0%B3-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3?".getBytes("UTF-8"); - byte[] cp1251_bytes = TypeUtil.fromHexString("e2fbe1f0e0edee3dd2e5ecefe5f0e0f2f3f0e0"); - String expectedCP1251String = new String(cp1251_bytes, "cp1251"); - String expectedCP1251Key = new String(cp1251_bytes, 0, 7, "cp1251"); - String expectedCP1251Value = new String(cp1251_bytes, 8, cp1251_bytes.length-8, "cp1251"); - - //paste both byte arrays together to form the uri - byte[] allbytes = new byte[utf8_bytes.length+cp1251_bytes.length]; - int i=0; - for (;i<utf8_bytes.length;i++) { - allbytes[i] = utf8_bytes[i]; - } - for (int j=0; j< cp1251_bytes.length;j++) - allbytes[i+j] = cp1251_bytes[j]; - - //Test using a HttpUri that expects a particular charset encoding. See URIUtil.__CHARSET - HttpURI uri = new HttpURI(Charset.forName("cp1251")); - uri.parse(allbytes, 0, allbytes.length); - assertEquals(expectedCP1251String, uri.getQuery("cp1251")); - - //Test params decoded correctly - MultiMap params = new MultiMap(); - uri.decodeQueryTo(params); - String val = params.getString(expectedCP1251Key); - assertNotNull(val); - assertEquals(expectedCP1251Value, val); - - //Test using HttpURI where you pass in the charset encoding. - HttpURI httpuri = new HttpURI(); - httpuri.parse(allbytes,0,allbytes.length); - assertNotNull(httpuri.getQuery("UTF-8")); //still get back a query string, just incorrectly encoded - assertEquals(expectedCP1251String, httpuri.getQuery("cp1251")); - - //Test params decoded correctly - params.clear(); - httpuri.decodeQueryTo(params, "cp1251"); - val = params.getString(expectedCP1251Key); - assertNotNull(val); - assertEquals(expectedCP1251Value, val); - - //test able to set the query encoding and call getQueryString multiple times - Request request = new Request(null,null); - request.setUri(httpuri); - request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1"); - assertNotNull (request.getQueryString()); //will be incorrect encoding but not null - request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251"); - assertEquals(expectedCP1251String, request.getQueryString()); - } - - @Test - public void testPercentEncodingOfQueryStringUsingNonUTF8() throws UnsupportedEncodingException - { - - byte[] utf8_bytes = "/%D0%A1%D1%82%D1%80%D0%BE%D0%BD%D0%B3-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3?".getBytes("UTF-8"); - byte[] cp1251_bytes = "%e2%fb%e1%f0%e0%ed%ee=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0".getBytes("cp1251"); - - byte[] key_bytes = TypeUtil.fromHexString("e2fbe1f0e0edee"); - byte[] val_bytes = TypeUtil.fromHexString("d2e5ecefe5f0e0f2f3f0e0"); - String expectedCP1251String = new String(cp1251_bytes, "cp1251"); - String expectedCP1251Key = new String(key_bytes, "cp1251"); - String expectedCP1251Value = new String(val_bytes, "cp1251"); - - byte[] allbytes = new byte[utf8_bytes.length+cp1251_bytes.length]; - - //stick both arrays together to form uri - int i=0; - for (;i<utf8_bytes.length;i++) { - allbytes[i] = utf8_bytes[i]; - } - for (int j=0; j< cp1251_bytes.length;j++) - allbytes[i+j] = cp1251_bytes[j]; - - - HttpURI httpuri = new HttpURI(); - httpuri.parse(allbytes,0,allbytes.length); - assertNotNull(httpuri.getQuery("UTF-8")); //will be incorrectly encoded, but no errors - assertEquals(expectedCP1251String, httpuri.getQuery("cp1251")); - - //test params decoded correctly - MultiMap params = new MultiMap(); - httpuri.decodeQueryTo(params, "cp1251"); - String val = params.getString(expectedCP1251Key); - assertNotNull(val); - assertEquals(expectedCP1251Value, val); - - //test able to set the query encoding and call getQueryString multiple times - Request request = new Request(null,null); - request.setUri(httpuri); - request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1"); - assertNotNull (request.getQueryString()); //will be incorrect encoding but not null - request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251"); - assertEquals(expectedCP1251String, request.getQueryString()); - - } - - @Test - public void testUnicodeErrors() throws UnsupportedEncodingException - { - String uri="http://server/path?invalid=data%uXXXXhere%u000"; - try - { - URLDecoder.decode(uri,"UTF-8"); - Assert.assertTrue(false); - } - catch (IllegalArgumentException e) - { - } - - HttpURI huri=new HttpURI(uri); - MultiMap<String> params = new MultiMap<>(); - huri.decodeQueryTo(params); - assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0)); - - huri=new HttpURI(uri); - params = new MultiMap<>(); - huri.decodeQueryTo(params,StandardCharsets.UTF_8); - assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0)); - - } - - @Test - public void testExtB() throws Exception - { - for (String value: new String[]{"a","abcdABCD","\u00C0","\u697C","\uD869\uDED5","\uD840\uDC08"} ) - { - HttpURI uri = new HttpURI("/path?value="+URLEncoder.encode(value,"UTF-8")); - - MultiMap<String> parameters = new MultiMap<>(); - uri.decodeQueryTo(parameters,StandardCharsets.UTF_8); - assertEquals(value,parameters.getString("value")); - } - } - - - private final String[][] connect_tests= - { - /* 0*/ {" localhost:8080 ","localhost","8080"}, - /* 1*/ {" 127.0.0.1:8080 ","127.0.0.1","8080"}, - /* 2*/ {" [127::0::0::1]:8080 ","[127::0::0::1]","8080"}, - /* 3*/ {" error ",null,null}, - /* 4*/ {" http://localhost:8080/ ",null,null}, - }; - - @Test - public void testCONNECT() throws Exception - { - HttpURI uri = new HttpURI(); - for (int i=0;i<connect_tests.length;i++) - { - try - { - byte[] buf = connect_tests[i][0].getBytes(StandardCharsets.UTF_8); - - uri.parseConnect(buf,2,buf.length-4); - assertEquals("path"+i,connect_tests[i][0].trim(),uri.getPath()); - assertEquals("host"+i,connect_tests[i][1],uri.getHost()); - assertEquals("port"+i,Integer.parseInt(connect_tests[i][2]),uri.getPort()); - } - catch(Exception e) - { - assertNull("error"+i,connect_tests[i][1]); - } - } - } - - @Test - public void testNonURIAscii() throws Exception - { - String url = "http://www.foo.com/ma\u00F1ana"; - byte[] asISO = url.getBytes(StandardCharsets.ISO_8859_1); - new String(asISO, StandardCharsets.ISO_8859_1); - - //use a non UTF-8 charset as the encoding and url-escape as per - //http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars - String s = URLEncoder.encode(url, "ISO-8859-1"); - HttpURI uri = new HttpURI(StandardCharsets.ISO_8859_1); - - //parse it, using the same encoding - uri.parse(s); - - //decode the url encoding - String d = URLDecoder.decode(uri.getCompletePath(), "ISO-8859-1"); - assertEquals(url, d); - } -} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 18811c52900..ab463c2a5fb 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -57,6 +57,7 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -297,9 +298,9 @@ public class RequestTest "Connection: close\n"+ "\n"; - LOG.info("Expecting NotUtf8Exception byte 62 in state 3..."); + LOG.info("Expecting NotUtf8Exception in state 36..."); String responses=_connector.getResponses(request); - assertTrue(responses.startsWith("HTTP/1.1 200")); + assertThat(responses,startsWith("HTTP/1.1 200")); } @Test diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextDispatchWithQueryStrings.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextDispatchWithQueryStrings.java index ce220866e06..d1c74280056 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextDispatchWithQueryStrings.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextDispatchWithQueryStrings.java @@ -18,7 +18,9 @@ package org.eclipse.jetty.servlet; +import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.IOException; @@ -35,7 +37,9 @@ import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerList; +import org.hamcrest.Matchers; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -43,69 +47,76 @@ import org.junit.Test; * This tests verifies that merging of queryStrings works when dispatching * Requests via {@link AsyncContext} multiple times. */ -public class AsyncContextDispatchWithQueryStrings { +public class AsyncContextDispatchWithQueryStrings +{ - private Server _server = new Server(); - private ServletContextHandler _contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); - private LocalConnector _connector = new LocalConnector(_server); + private Server _server = new Server(); + private ServletContextHandler _contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); + private LocalConnector _connector = new LocalConnector(_server); - @Before - public void setUp() throws Exception { - _connector.setIdleTimeout(30000); - _server.setConnectors(new Connector[] { _connector }); + @Before + public void setUp() throws Exception + { + _connector.setIdleTimeout(30000); + _server.setConnectors(new Connector[] { _connector }); - _contextHandler.setContextPath("/"); - _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/initialCall"); - _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/firstDispatchWithNewQueryString"); - _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/secondDispatchNewValueForExistingQueryString"); + _contextHandler.setContextPath("/"); + _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/initialCall"); + _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/firstDispatchWithNewQueryString"); + _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/secondDispatchNewValueForExistingQueryString"); - HandlerList handlers = new HandlerList(); - handlers.setHandlers(new Handler[] { _contextHandler, new DefaultHandler() }); + HandlerList handlers = new HandlerList(); + handlers.setHandlers(new Handler[] { _contextHandler, new DefaultHandler() }); - _server.setHandler(handlers); - _server.start(); - } + _server.setHandler(handlers); + _server.start(); + } - @Test - public void testMultipleDispatchesWithNewQueryStrings() throws Exception { - String request = "GET /initialCall?initialParam=right HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" - + "Connection: close\r\n" + "\r\n"; - String responseString = _connector.getResponses(request); - assertTrue("Not the expected response. Check STDOUT for details.", responseString.startsWith("HTTP/1.1 200")); - } + @Test + public void testMultipleDispatchesWithNewQueryStrings() throws Exception { + String request = + "GET /initialCall?initialParam=right HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Content-Type: application/x-www-form-urlencoded\r\n" + + "Connection: close\r\n" + "\r\n"; + String responseString = _connector.getResponses(request); + assertThat(responseString,startsWith("HTTP/1.1 200")); + } - @After - public void tearDown() throws Exception { - _server.stop(); - _server.join(); - } + @After + public void tearDown() throws Exception { + _server.stop(); + _server.join(); + } - private class TestServlet extends HttpServlet { - private static final long serialVersionUID = 1L; + private class TestServlet extends HttpServlet + { + private static final long serialVersionUID = 1L; - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String path = request.getRequestURI(); - String queryString = request.getQueryString(); - if ("/initialCall".equals(path)) - { - AsyncContext async = request.startAsync(); - async.dispatch("/firstDispatchWithNewQueryString?newQueryString=initialValue"); - assertEquals("initialParam=right", queryString); - } - else if ("/firstDispatchWithNewQueryString".equals(path)) - { - AsyncContext async = request.startAsync(); - async.dispatch("/secondDispatchNewValueForExistingQueryString?newQueryString=newValue"); - assertEquals("newQueryString=initialValue&initialParam=right", queryString); - } - else - { - response.setContentType("text/html"); - response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().println("<h1>woohhooooo</h1>"); - assertEquals("newQueryString=newValue&initialParam=right", queryString); - } - } - } + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + String uri = request.getRequestURI(); + String queryString = request.getQueryString(); + if ("/initialCall".equals(uri)) + { + AsyncContext async = request.startAsync(); + async.dispatch("/firstDispatchWithNewQueryString?newQueryString=initialValue"); + assertEquals("initialParam=right", queryString); + } + else if ("/firstDispatchWithNewQueryString".equals(uri)) + { + AsyncContext async = request.startAsync(); + async.dispatch("/secondDispatchNewValueForExistingQueryString?newQueryString=newValue"); + assertEquals("newQueryString=initialValue&initialParam=right", queryString); + } + else + { + response.setContentType("text/html"); + response.setStatus(HttpServletResponse.SC_OK); + response.getWriter().println("<h1>woohhooooo</h1>"); + assertEquals("newQueryString=newValue&initialParam=right", queryString); + } + } + } } diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java index d6126466732..8cc231a3913 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java @@ -154,14 +154,6 @@ public class DefaultServletTest String response = connector.getResponses(req1.toString()); - assertResponseContains("/one/", response); - assertResponseContains("/two/", response); - assertResponseContains("/three/", response); - if (!OS.IS_WINDOWS) - { - assertResponseContains("/f%3F%3Fr", response); - } - assertResponseNotContains("<script>", response); } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index 0be51494cfb..ca1353d2104 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -25,6 +25,7 @@ import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -104,7 +105,6 @@ public class HttpChannelOverSPDY extends HttpChannel HttpMethod httpMethod = HttpMethod.fromString(methodHeader.getValue()); HttpVersion httpVersion = HttpVersion.fromString(versionHeader.getValue()); - HttpURI uri = new HttpURI(uriHeader.getValue()); if (LOG.isDebugEnabled()) LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion); @@ -164,7 +164,7 @@ public class HttpChannelOverSPDY extends HttpChannel // At last, add the Host header. fields.add(hostPort); - MetaData.Request request = new FinalMetaData.Request(httpVersion, httpMethod.asString(), uri, fields, hostPort); + MetaData.Request request = new FinalMetaData.Request(httpVersion, HttpScheme.HTTP.asString(), httpMethod==null?methodHeader.getValue():httpMethod.asString(), uriHeader.getValue(), fields, hostPort); onRequest(request); return true; } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java index d4a5d84a434..f965135fa80 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java @@ -29,7 +29,6 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; @@ -81,7 +80,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse } @Override - public boolean startRequest(String methodString, HttpURI uri, HttpVersion httpVersion) + public boolean startRequest(String methodString, String uri, HttpVersion httpVersion) { Connector connector = getConnector(); String scheme = connector.getConnectionFactory(SslConnectionFactory.class) != null ? "https" : "http"; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index d30ad320f9b..de72e884d0e 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -357,6 +357,19 @@ public class TypeUtil return b; } + /* ------------------------------------------------------------ */ + /** + * @param c An ASCII encoded character 0-9 a-f A-F + * @return The byte value of the character 0-16. + */ + public static int convertHexDigit( char c ) + { + int d= ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10); + if (d<0 || d>15) + throw new NumberFormatException("!hex "+c); + return d; + } + /* ------------------------------------------------------------ */ /** * @param c An ASCII encoded character 0-9 a-f A-F diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java index ca2013830c2..67e2eab38c1 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java @@ -19,12 +19,17 @@ package org.eclipse.jetty.util; import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; import java.nio.charset.StandardCharsets; +import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + /* ------------------------------------------------------------ */ -/** URI Holder. +/** URI Utility methods. * This class assists with the decoding and encoding or HTTP URI's. * It differs from the java.net.URL class as it does not provide * communications ability, but it does assist with query string @@ -37,6 +42,7 @@ import java.nio.charset.StandardCharsets; public class URIUtil implements Cloneable { + private static final Logger LOG = Log.getLogger(URIUtil.class); public static final String SLASH="/"; public static final String HTTP="http"; public static final String HTTP_COLON="http:"; @@ -44,13 +50,7 @@ public class URIUtil public static final String HTTPS_COLON="https:"; // Use UTF-8 as per http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars - public static final Charset __CHARSET; - - static - { - String charset = System.getProperty("org.eclipse.jetty.util.URI.charset"); - __CHARSET = charset == null ? StandardCharsets.UTF_8 : Charset.forName(charset); - } + public static final Charset __CHARSET=StandardCharsets.UTF_8 ; private URIUtil() {} @@ -254,123 +254,163 @@ public class URIUtil /* ------------------------------------------------------------ */ /* Decode a URI path and strip parameters - * @param path The path the encode - * @param buf StringBuilder to encode path into */ public static String decodePath(String path) { - if (path==null) - return null; - // Array to hold all converted characters - char[] chars=null; - int n=0; - // Array to hold a sequence of %encodings - byte[] bytes=null; - int b=0; - - int len=path.length(); - - for (int i=0;i<len;i++) - { - char c = path.charAt(i); - - if (c=='%' && (i+2)<len) - { - if (chars==null) - { - chars=new char[len]; - bytes=new byte[len]; - path.getChars(0,i,chars,0); - } - bytes[b++]=(byte)(0xff&TypeUtil.parseInt(path,i+1,2,16)); - i+=2; - continue; - } - else if (c==';') - { - if (chars==null) - { - chars=new char[len]; - path.getChars(0,i,chars,0); - n=i; - } - break; - } - else if (bytes==null) - { - n++; - continue; - } - - // Do we have some bytes to convert? - if (b>0) - { - String s=new String(bytes,0,b,__CHARSET); - s.getChars(0,s.length(),chars,n); - n+=s.length(); - b=0; - } - - chars[n++]=c; - } - - if (chars==null) - return path; - - // if we have a remaining sequence of bytes - if (b>0) - { - String s=new String(bytes,0,b,__CHARSET); - s.getChars(0,s.length(),chars,n); - n+=s.length(); - } - - return new String(chars,0,n); + return decodePath(path,0,path.length()); } + + /* ------------------------------------------------------------ */ + /* Decode a URI path and strip parameters of UTF-8 path + */ + public static String decodePath(String path, int offset, int length) + { + try + { + Utf8StringBuilder builder=null; + int end=offset+length; + for (int i=offset;i<end;i++) + { + char c = path.charAt(i); + switch(c) + { + case '%': + if (builder==null) + { + builder=new Utf8StringBuilder(path.length()); + builder.append(path,offset,i-offset); + } + if ((i+2)<end) + { + char u=path.charAt(i+1); + if (u=='u') + { + // TODO this is wrong. This is a codepoint not a char + builder.append((char)(0xffff&TypeUtil.parseInt(path,i+2,4,16))); + i+=5; + } + else + { + builder.append((byte)(0xff&(TypeUtil.convertHexDigit(u)*16+TypeUtil.convertHexDigit(path.charAt(i+2))))); + i+=2; + } + } + else + { + throw new IllegalArgumentException(); + } + + break; + + case ';': + if (builder==null) + { + builder=new Utf8StringBuilder(path.length()); + builder.append(path,offset,i-offset); + } + + while(++i<end) + { + if (path.charAt(i)=='/') + { + builder.append('/'); + break; + } + } + + break; + + default: + if (builder!=null) + builder.append(c); + break; + } + } + + if (builder!=null) + return builder.toString(); + if (offset==0 && length==path.length()) + return path; + return path.substring(offset,end); + } + catch(NotUtf8Exception e) + { + LOG.warn(path.substring(offset,offset+length)+" "+e); + LOG.debug(e); + return decodeISO88591Path(path,offset,length); + } + } + /* ------------------------------------------------------------ */ - /* Decode a URI path and strip parameters. - * @param path The path the encode - * @param buf StringBuilder to encode path into + /* Decode a URI path and strip parameters of ISO-8859-1 path */ - public static String decodePath(byte[] buf, int offset, int length) + private static String decodeISO88591Path(String path, int offset, int length) { - byte[] bytes=null; - int n=0; - - for (int i=0;i<length;i++) + StringBuilder builder=null; + int end=offset+length; + for (int i=offset;i<end;i++) { - byte b = buf[i + offset]; - - if (b=='%' && (i+2)<length) + char c = path.charAt(i); + switch(c) { - b=(byte)(0xff&TypeUtil.parseInt(buf,i+offset+1,2,16)); - i+=2; + case '%': + if (builder==null) + { + builder=new StringBuilder(path.length()); + builder.append(path,offset,i-offset); + } + if ((i+2)<end) + { + char u=path.charAt(i+1); + if (u=='u') + { + // TODO this is wrong. This is a codepoint not a char + builder.append((char)(0xffff&TypeUtil.parseInt(path,i+2,4,16))); + i+=5; + } + else + { + builder.append((byte)(0xff&(TypeUtil.convertHexDigit(u)*16+TypeUtil.convertHexDigit(path.charAt(i+2))))); + i+=2; + } + } + else + { + throw new IllegalArgumentException(); + } + + break; + + case ';': + if (builder==null) + { + builder=new StringBuilder(path.length()); + builder.append(path,offset,i-offset); + } + while(++i<end) + { + if (path.charAt(i)=='/') + { + builder.append('/'); + break; + } + } + break; + + + default: + if (builder!=null) + builder.append(c); + break; } - else if (b==';') - { - length=i; - break; - } - else if (bytes==null) - { - n++; - continue; - } - - if (bytes==null) - { - bytes=new byte[length]; - for (int j=0;j<n;j++) - bytes[j]=buf[j + offset]; - } - - bytes[n++]=b; } - if (bytes==null) - return new String(buf,offset,length,__CHARSET); - return new String(bytes,0,n,__CHARSET); + if (builder!=null) + return builder.toString(); + if (offset==0 && length==path.length()) + return path; + return path.substring(offset,end); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java index 90074e2b400..adf1b770d33 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java @@ -87,19 +87,19 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable public UrlEncoded(String query) { - decodeTo(query,this,ENCODING,-1); + decodeTo(query,this,ENCODING); } /* ----------------------------------------------------------------- */ public void decode(String query) { - decodeTo(query,this,ENCODING,-1); + decodeTo(query,this,ENCODING); } /* ----------------------------------------------------------------- */ public void decode(String query,Charset charset) { - decodeTo(query,this,charset,-1); + decodeTo(query,this,charset); } /* -------------------------------------------------------------- */ @@ -191,20 +191,26 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable /** Decoded parameters to Map. * @param content the string containing the encoded parameters */ - public static void decodeTo(String content, MultiMap<String> map, String charset, int maxKeys) + public static void decodeTo(String content, MultiMap<String> map, String charset) { - decodeTo(content,map,charset==null?null:Charset.forName(charset),maxKeys); + decodeTo(content,map,charset==null?null:Charset.forName(charset)); } /* -------------------------------------------------------------- */ /** Decoded parameters to Map. * @param content the string containing the encoded parameters */ - public static void decodeTo(String content, MultiMap<String> map, Charset charset, int maxKeys) + public static void decodeTo(String content, MultiMap<String> map, Charset charset) { if (charset==null) charset=ENCODING; + if (charset==StandardCharsets.UTF_8) + { + decodeUtf8To(content,0,content.length(),map); + return; + } + synchronized(map) { String key = null; @@ -232,8 +238,6 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable } key = null; value=null; - if (maxKeys>0 && map.size()>maxKeys) - throw new IllegalStateException("Form too many keys"); break; case '=': if (key!=null) @@ -270,6 +274,12 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable } } + /* -------------------------------------------------------------- */ + public static void decodeUtf8To(String query, MultiMap<String> map) + { + decodeUtf8To(query,0,query.length(),map); + } + /* -------------------------------------------------------------- */ /** Decoded parameters to Map. * @param raw the byte[] containing the encoded parameters @@ -277,7 +287,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable * @param length the length of the section to decode * @param map the {@link MultiMap} to populate */ - public static void decodeUtf8To(byte[] raw,int offset, int length, MultiMap<String> map) + public static void decodeUtf8To(String query,int offset, int length, MultiMap<String> map) { Utf8StringBuilder buffer = new Utf8StringBuilder(); synchronized(map) @@ -288,10 +298,10 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable int end=offset+length; for (int i=offset;i<end;i++) { - byte b=raw[i]; + char c=query.charAt(i); try { - switch ((char)(0xff&b)) + switch (c) { case '&': value = buffer.toReplacedString(); @@ -311,7 +321,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable case '=': if (key!=null) { - buffer.append(b); + buffer.append(c); break; } key = buffer.toReplacedString(); @@ -325,15 +335,15 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable case '%': if (i+2<end) { - if ('u'==raw[i+1]) + if ('u'==query.charAt(i+1)) { i++; if (i+4<end) { - byte top=raw[++i]; - byte hi=raw[++i]; - byte lo=raw[++i]; - byte bot=raw[++i]; + char top=query.charAt(++i); + char hi=query.charAt(++i); + char lo=query.charAt(++i); + char bot=query.charAt(++i); buffer.getStringBuilder().append(Character.toChars((convertHexDigit(top)<<12) +(convertHexDigit(hi)<<8) + (convertHexDigit(lo)<<4) +convertHexDigit(bot))); } else @@ -344,8 +354,8 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable } else { - byte hi=raw[++i]; - byte lo=raw[++i]; + char hi=query.charAt(++i); + char lo=query.charAt(++i); buffer.append((byte)((convertHexDigit(hi)<<4) + convertHexDigit(lo))); } } @@ -357,7 +367,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable break; default: - buffer.append(b); + buffer.append(c); break; } } @@ -620,7 +630,8 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable StringWriter buf = new StringWriter(8192); IO.copy(input,buf,maxLength); - decodeTo(buf.getBuffer().toString(),map,StandardCharsets.UTF_16,maxKeys); + // TODO implement maxKeys + decodeTo(buf.getBuffer().toString(),map,StandardCharsets.UTF_16); } /* -------------------------------------------------------------- */ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java index ff58764ad7d..a1a70d927cc 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java @@ -98,6 +98,58 @@ public abstract class Utf8Appendable _state = UTF8_ACCEPT; } + + private void checkCharAppend() throws IOException + { + if (_state != UTF8_ACCEPT) + { + _appendable.append(REPLACEMENT); + int state=_state; + _state=UTF8_ACCEPT; + throw new NotUtf8Exception("char appended in state "+state); + } + } + + public void append(char c) + { + try + { + checkCharAppend(); + _appendable.append(c); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void append(String s) + { + try + { + checkCharAppend(); + _appendable.append(s); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void append(String s,int offset,int length) + { + try + { + checkCharAppend(); + _appendable.append(s,offset,offset+length); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void append(byte b) { try diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java index e2b4955dc77..13f2165aa85 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java @@ -60,8 +60,15 @@ public class URIUtilTest @Test public void testDecodePath() { + assertEquals("/foo/bar",URIUtil.decodePath("xx/foo/barxx",2,8)); + assertEquals("/foo/bar",URIUtil.decodePath("/foo/bar")); + assertEquals("/f o/b r",URIUtil.decodePath("/f%20o/b%20r")); + assertEquals("/foo/bar",URIUtil.decodePath("/foo;ignore/bar;ignore")); + assertEquals("/fää/bar",URIUtil.decodePath("/fää;ignore/bar;ignore")); + assertEquals("/f\u0629\u0629%23/bar",URIUtil.decodePath("/f%d8%a9%d8%a9%2523;ignore/bar;ignore")); + assertEquals("foo%23;,:=b a r",URIUtil.decodePath("foo%2523%3b%2c:%3db%20a%20r;rubbish")); - assertEquals("foo%23;,:=b a r=",URIUtil.decodePath("xxxfoo%2523%3b%2c:%3db%20a%20r%3Dxxx;rubbish".getBytes(),3,30)); + assertEquals("/foo/bar%23;,:=b a r=",URIUtil.decodePath("xxx/foo/bar%2523%3b%2c:%3db%20a%20r%3Dxxx;rubbish",3,35)); assertEquals("fää%23;,:=b a r=",URIUtil.decodePath("fää%2523%3b%2c:%3db%20a%20r%3D")); assertEquals("f\u0629\u0629%23;,:=b a r",URIUtil.decodePath("f%d8%a9%d8%a9%2523%3b%2c:%3db%20a%20r")); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java index 297b8e14027..f6a693269b1 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java @@ -165,9 +165,9 @@ public class URLEncodedTest assertEquals("encoded param size",1, url_encoded.size()); assertEquals("encoded get", "xx\ufffdyy", url_encoded.getString("Name15")); - byte[] bad="Name=%FF%FF%FF".getBytes(StandardCharsets.UTF_8); + String bad="Name=%FF%FF%FF"; MultiMap<String> map = new MultiMap<String>(); - UrlEncoded.decodeUtf8To(bad,0,bad.length,map); + UrlEncoded.decodeUtf8To(bad,map); assertEquals("encoded param size",1, map.size()); assertEquals("encoded get", "\ufffd\ufffd\ufffd", map.getString("Name")); @@ -214,7 +214,7 @@ public class URLEncodedTest { ByteArrayInputStream in = new ByteArrayInputStream(("name\n=value+"+charsets[i][2]+"&name1=&name2&n\u00e3me3=value+3").getBytes(charsets[i][0])); MultiMap<String> m = new MultiMap<>(); - UrlEncoded.decodeTo(in, m, charsets[i][1]==null?null:Charset.forName(charsets[i][1]), -1,-1); + UrlEncoded.decodeTo(in, m, charsets[i][1]==null?null:Charset.forName(charsets[i][1]),-1,-1); assertEquals(charsets[i][1]+" stream length",4,m.size()); assertEquals(charsets[i][1]+" stream name\\n","value 0",m.getString("name\n")); assertEquals(charsets[i][1]+" stream name1","",m.getString("name1")); @@ -227,7 +227,7 @@ public class URLEncodedTest { ByteArrayInputStream in2 = new ByteArrayInputStream("name=%83e%83X%83g".getBytes(StandardCharsets.ISO_8859_1)); MultiMap<String> m2 = new MultiMap<>(); - UrlEncoded.decodeTo(in2, m2, Charset.forName("Shift_JIS"), -1,-1); + UrlEncoded.decodeTo(in2, m2, Charset.forName("Shift_JIS"),-1,-1); assertEquals("stream length",1,m2.size()); assertEquals("stream name","\u30c6\u30b9\u30c8",m2.getString("name")); } @@ -279,12 +279,12 @@ public class URLEncodedTest MultiMap<String> map = new MultiMap<>(); UrlEncoded.LOG.info("EXPECT 4 Not Valid UTF8 warnings..."); - UrlEncoded.decodeUtf8To(query.getBytes(StandardCharsets.ISO_8859_1),0,query.length(),map); + UrlEncoded.decodeUtf8To(query,0,query.length(),map); assertEquals("X"+Utf8Appendable.REPLACEMENT+Utf8Appendable.REPLACEMENT+"Z",map.getValue("name",0)); map.clear(); - UrlEncoded.decodeUtf8To(new ByteArrayInputStream(query.getBytes(StandardCharsets.ISO_8859_1)),map,100,2); + UrlEncoded.decodeUtf8To(new ByteArrayInputStream(query.getBytes(StandardCharsets.ISO_8859_1)),map,100,-1); assertEquals("X"+Utf8Appendable.REPLACEMENT+Utf8Appendable.REPLACEMENT+"Z",map.getValue("name",0)); } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/UrlEncodedUtf8Test.java b/jetty-util/src/test/java/org/eclipse/jetty/util/UrlEncodedUtf8Test.java index a80c51c5e65..0b015096ccb 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/UrlEncodedUtf8Test.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/UrlEncodedUtf8Test.java @@ -40,7 +40,7 @@ public class UrlEncodedUtf8Test String test=new String(bytes,StandardCharsets.UTF_8); String expected = "c"+Utf8Appendable.REPLACEMENT; - fromByteArray(test,bytes,"ab",expected,false); + fromString(test,test,"ab",expected,false); fromInputStream(test,bytes,"ab",expected,false); } @@ -51,7 +51,7 @@ public class UrlEncodedUtf8Test String test=new String(bytes,StandardCharsets.UTF_8); String expected = ""+Utf8Appendable.REPLACEMENT; - fromByteArray(test,bytes,"ab",expected,false); + fromString(test,test,"ab",expected,false); fromInputStream(test,bytes,"ab",expected,false); } @@ -64,7 +64,7 @@ public class UrlEncodedUtf8Test String name = "e"+Utf8Appendable.REPLACEMENT; String value = "fg"; - fromByteArray(test,bytes,name,value,false); + fromString(test,test,name,value,false); fromInputStream(test,bytes,name,value,false); } @@ -76,9 +76,8 @@ public class UrlEncodedUtf8Test String name = "ef"; String value = "g"+Utf8Appendable.REPLACEMENT; - fromByteArray(test,bytes,name,value,false); + fromString(test,test,name,value,false); fromInputStream(test,bytes,name,value,false); - } @Test @@ -90,9 +89,8 @@ public class UrlEncodedUtf8Test String name = "a"; String value = "a"; - fromByteArray(test,bytes,name,value,false); + fromString(test,test,name,value,false); fromInputStream(test,bytes,name,value,false); - } @Test @@ -104,9 +102,8 @@ public class UrlEncodedUtf8Test String name = "a"; String value = ""+Utf8Appendable.REPLACEMENT; - fromByteArray(test,bytes,name,value,false); + fromString(test,test,name,value,false); fromInputStream(test,bytes,name,value,false); - } @Test @@ -118,18 +115,16 @@ public class UrlEncodedUtf8Test String name = "a"; String value = ""+Utf8Appendable.REPLACEMENT; - fromByteArray(test,bytes,name,value,false); + fromString(test,test,name,value,false); fromInputStream(test,bytes,name,value,false); - } - static void fromByteArray(String test,byte[] b,String field,String expected,boolean thrown) throws Exception + static void fromString(String test,String s,String field,String expected,boolean thrown) throws Exception { MultiMap<String> values=new MultiMap<>(); try { - //safeDecodeUtf8To(b, 0, b.length, values); - UrlEncoded.decodeUtf8To(b, 0, b.length, values); + UrlEncoded.decodeUtf8To(s, 0, s.length(), values); if (thrown) Assert.fail(); Assert.assertEquals(test, expected, values.getString(field)); @@ -148,8 +143,7 @@ public class UrlEncodedUtf8Test MultiMap<String> values=new MultiMap<>(); try { - //safeDecodeUtf8To(is, values, 1000000, 10000000); - UrlEncoded.decodeUtf8To(is, values, 1000000, 10000000); + UrlEncoded.decodeUtf8To(is, values, 1000000,-1); if (thrown) Assert.fail(); Assert.assertEquals(test, expected, values.getString(field)); diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java index 4993bf561f9..c41d0ff94f3 100644 --- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java +++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java @@ -46,7 +46,6 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; public class ClientUpgradeRequest extends UpgradeRequest { private static final Logger LOG = Log.getLogger(ClientUpgradeRequest.class); - private static final int MAX_KEYS = -1; // maximum number of parameter keys to decode private static final Set<String> FORBIDDEN_HEADERS; static @@ -239,7 +238,7 @@ public class ClientUpgradeRequest extends UpgradeRequest if (StringUtil.isNotBlank(query)) { MultiMap<String> params = new MultiMap<String>(); - UrlEncoded.decodeTo(uri.getQuery(),params,StandardCharsets.UTF_8,MAX_KEYS); + UrlEncoded.decodeTo(uri.getQuery(),params,StandardCharsets.UTF_8); for (String key : params.keySet()) { From 4f88f2fce2cd6e8b1d910b37c85d98d8a79587b9 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Mon, 21 Jul 2014 15:51:44 -0700 Subject: [PATCH 146/269] Fixing build + Quick start example is now in /examples/quickstart/ to avoid dependency loop + Forgotten tests are now versioned correctly at 9.3.0 --- examples/pom.xml | 1 + examples/quickstart/pom.xml | 169 ++++++++++++++++++ jetty-quickstart/pom.xml | 70 +------- .../test-mongodb-sessions/pom.xml | 2 +- .../test-webapps/test-dispatch-webapp/pom.xml | 2 +- 5 files changed, 173 insertions(+), 71 deletions(-) create mode 100644 examples/quickstart/pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 613daa27629..02fa8da6294 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -47,5 +47,6 @@ --> <module>async-rest</module> <module>embedded</module> + <module>quickstart</module> </modules> </project> diff --git a/examples/quickstart/pom.xml b/examples/quickstart/pom.xml new file mode 100644 index 00000000000..0ec830114c6 --- /dev/null +++ b/examples/quickstart/pom.xml @@ -0,0 +1,169 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>org.eclipse.jetty.examples</groupId> + <artifactId>examples-parent</artifactId> + <version>9.3.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>example-jetty-quickstart</artifactId> + <name>Example :: Jetty Quick Start</name> + <description>Jetty Quick Start Example</description> + <url>http://www.eclipse.org/jetty</url> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-jmx</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-plus</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-annotations</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>javax.transaction</groupId> + <artifactId>javax.transaction-api</artifactId> + <version>1.2</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>test-mock-resources</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.mail.glassfish</artifactId> + <version>1.4.1.v201005082020</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlets</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>test-jndi-webapp</artifactId> + <version>${project.version}</version> + <type>war</type> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.websocket</groupId> + <artifactId>javax-websocket-server-impl</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.websocket</groupId> + <artifactId>websocket-server</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>apache-jsp</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>apache-jstl</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>appassembler-maven-plugin</artifactId> + <version>1.7</version> + <configuration> + <platforms> + <platform>unix</platform> + </platforms> + <programs> + <program> + <id>preconfigure</id> + <mainClass>org.eclipse.jetty.quickstart.PreconfigureQuickStartWar</mainClass> + </program> + <program> + <mainClass>org.eclipse.jetty.quickstart.QuickStartWar</mainClass> + <id>quickstart</id> + </program> + </programs> + </configuration> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </plugin> + + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy</id> + <phase>generate-resources</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>test-jndi-webapp</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <includes>**</includes> + <outputDirectory>${basedir}/target</outputDirectory> + <destFileName>test-jndi.war</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>test-spec-webapp</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <includes>**</includes> + <outputDirectory>${basedir}/target</outputDirectory> + <destFileName>test-spec.war</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.eclipse.jetty</groupId> + <artifactId>test-jetty-webapp</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <includes>**</includes> + <outputDirectory>${basedir}/target</outputDirectory> + <destFileName>test-standard.war</destFileName> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/jetty-quickstart/pom.xml b/jetty-quickstart/pom.xml index a6f3314e4bd..a67e95337dd 100644 --- a/jetty-quickstart/pom.xml +++ b/jetty-quickstart/pom.xml @@ -7,7 +7,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-quickstart</artifactId> - <name>Example :: Jetty Quick Start</name> + <name>Jetty :: Quick Start</name> <description>Jetty Quick Start</description> <url>http://www.eclipse.org/jetty</url> <dependencies> @@ -82,74 +82,6 @@ </dependencies> <build> <plugins> - - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>appassembler-maven-plugin</artifactId> - <version>1.7</version> - <configuration> - <platforms> - <platform>unix</platform> - </platforms> - <programs> - <program> - <id>preconfigure</id> - <mainClass>org.eclipse.jetty.quickstart.PreconfigureQuickStartWar</mainClass> - </program> - <program> - <mainClass>org.eclipse.jetty.quickstart.QuickStartWar</mainClass> - <id>quickstart</id> - </program> - </programs> - </configuration> - </plugin> - - <plugin> - <artifactId>maven-dependency-plugin</artifactId> - <executions> - <execution> - <id>copy</id> - <phase>generate-resources</phase> - <goals> - <goal>copy</goal> - </goals> - <configuration> - <artifactItems> - <artifactItem> - <groupId>org.eclipse.jetty.tests</groupId> - <artifactId>test-jndi-webapp</artifactId> - <version>${project.version}</version> - <type>war</type> - <overWrite>true</overWrite> - <includes>**</includes> - <outputDirectory>${basedir}/target</outputDirectory> - <destFileName>test-jndi.war</destFileName> - </artifactItem> - <artifactItem> - <groupId>org.eclipse.jetty.tests</groupId> - <artifactId>test-spec-webapp</artifactId> - <version>${project.version}</version> - <type>war</type> - <overWrite>true</overWrite> - <includes>**</includes> - <outputDirectory>${basedir}/target</outputDirectory> - <destFileName>test-spec.war</destFileName> - </artifactItem> - <artifactItem> - <groupId>org.eclipse.jetty</groupId> - <artifactId>test-jetty-webapp</artifactId> - <version>${project.version}</version> - <type>war</type> - <overWrite>true</overWrite> - <includes>**</includes> - <outputDirectory>${basedir}/target</outputDirectory> - <destFileName>test-standard.war</destFileName> - </artifactItem> - </artifactItems> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/tests/test-sessions/test-mongodb-sessions/pom.xml b/tests/test-sessions/test-mongodb-sessions/pom.xml index 2d41a6607a6..e08bc42b7ef 100644 --- a/tests/test-sessions/test-mongodb-sessions/pom.xml +++ b/tests/test-sessions/test-mongodb-sessions/pom.xml @@ -21,7 +21,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.2.0-SNAPSHOT</version> + <version>9.3.0-SNAPSHOT</version> </parent> <artifactId>test-mongodb-sessions</artifactId> <name>Jetty Tests :: Sessions :: Mongo</name> diff --git a/tests/test-webapps/test-dispatch-webapp/pom.xml b/tests/test-webapps/test-dispatch-webapp/pom.xml index b5b77e6e3dd..497fdd572d6 100644 --- a/tests/test-webapps/test-dispatch-webapp/pom.xml +++ b/tests/test-webapps/test-dispatch-webapp/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.2.0-SNAPSHOT</version> + <version>9.3.0-SNAPSHOT</version> </parent> <name>Jetty Tests :: Webapps :: Dispatch Webapp</name> <artifactId>test-dispatch-webapp</artifactId> From 8ec4e56681231a2370715cde72d46262aba65294 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Tue, 22 Jul 2014 11:57:52 -0700 Subject: [PATCH 147/269] Fixing compile error --- .../osgi/boot/warurl/internal/WarBundleManifestGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java index 015a1d2044f..d008ab52836 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java +++ b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java @@ -259,7 +259,7 @@ public class WarBundleManifestGenerator { poundIndex = url.length(); } - UrlEncoded.decodeUtf8To(url.getBytes(), questionMarkIndex+1, + UrlEncoded.decodeUtf8To(url, questionMarkIndex+1, poundIndex - questionMarkIndex - 1, res); return res; } From d6f841bb8736913f8934a0e99f24fd26affc1979 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 23 Jul 2014 09:03:33 +1000 Subject: [PATCH 148/269] fixed refactor uri issue --- .../src/main/java/org/eclipse/jetty/http2/parser/Parser.java | 3 ++- .../main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java | 4 +++- .../java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index b0d8751ad86..9314291bde3 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -153,7 +153,7 @@ public class Parser catch (Throwable x) { LOG.debug(x); - notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "parser_error"); + notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "parser_error: "+x); return false; } } @@ -251,6 +251,7 @@ public class Parser @Override public void onConnectionFailure(int error, String reason) { + LOG.warn("onConnectionFailure {},{}",error,reason); } } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 82efe316c36..ff376a57678 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -189,9 +189,11 @@ public class HpackDecoder break; case ":path": + // TODO is this needed + /* if (indexed) field = new StaticValueHttpField(header,name,value,new HttpURI(value)); - else + else*/ field = new HttpField(header,name,value); break; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 9d2bac4873e..aa09a31f80f 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -92,7 +92,7 @@ public class MetaDataBuilder break; default: - throw new IllegalArgumentException(); + throw new IllegalArgumentException(field.getName()); } } else From 07edbea6fec3b6078ff7606e5e2ee5909145b41d Mon Sep 17 00:00:00 2001 From: Jan Bartel <janb@intalio.com> Date: Wed, 23 Jul 2014 11:26:18 +1000 Subject: [PATCH 149/269] 439369 Remove unused class CrossContextPsuedoSession --- .../jaspi/modules/FormAuthModule.java | 30 ------ .../security/CrossContextPsuedoSession.java | 37 ------- .../HashCrossContextPsuedoSession.java | 100 ------------------ 3 files changed, 167 deletions(-) delete mode 100644 jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java delete mode 100644 jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java index 9215eddaf00..cc87cedff8e 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java @@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.security.CrossContextPsuedoSession; import org.eclipse.jetty.security.authentication.DeferredAuthentication; import org.eclipse.jetty.security.authentication.LoginCallbackImpl; import org.eclipse.jetty.security.authentication.SessionAuthentication; @@ -79,7 +78,6 @@ public class FormAuthModule extends BaseAuthModule private String _formLoginPath; - private CrossContextPsuedoSession<UserInfo> ssoSource; public FormAuthModule() { @@ -92,17 +90,6 @@ public class FormAuthModule extends BaseAuthModule setErrorPage(errorPage); } - /** - * @deprecated - */ - public FormAuthModule(CallbackHandler callbackHandler, CrossContextPsuedoSession<UserInfo> ssoSource, - String loginPage, String errorPage) - { - super(callbackHandler); - this.ssoSource = ssoSource; - setLoginPage(loginPage); - setErrorPage(errorPage); - } @Override public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, @@ -112,7 +99,6 @@ public class FormAuthModule extends BaseAuthModule super.initialize(requestPolicy, responsePolicy, handler, options); setLoginPage((String) options.get(LOGIN_PAGE_KEY)); setErrorPage((String) options.get(ERROR_PAGE_KEY)); - ssoSource = (CrossContextPsuedoSession<UserInfo>) options.get(SSO_SOURCE_KEY); } private void setLoginPage(String path) @@ -231,17 +217,7 @@ public class FormAuthModule extends BaseAuthModule return AuthStatus.SUCCESS; } - else if (ssoSource != null) - { - UserInfo userInfo = ssoSource.fetch(request); - if (userInfo != null) - { - boolean success = tryLogin(messageInfo, clientSubject, response, session, userInfo.getUserName(), new Password(new String(userInfo.getPassword()))); - if (success) { return AuthStatus.SUCCESS; } - } - } - // if we can't send challenge if (DeferredAuthentication.isDeferred(response)) @@ -310,12 +286,6 @@ public class FormAuthModule extends BaseAuthModule } } - // Sign-on to SSO mechanism - if (ssoSource != null) - { - UserInfo userInfo = new UserInfo(username, pwdChars); - ssoSource.store(userInfo, response); - } return true; } return false; diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java deleted file mode 100644 index a67eb96d6fc..00000000000 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java +++ /dev/null @@ -1,37 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.security; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $ - * @deprecated - */ -public interface CrossContextPsuedoSession<T> -{ - - T fetch(HttpServletRequest request); - - void store(T data, HttpServletResponse response); - - void clear(HttpServletRequest request); - -} diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java deleted file mode 100644 index 2f94908acb3..00000000000 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java +++ /dev/null @@ -1,100 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.security; - -import java.security.SecureRandom; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $ - * @deprecated - */ -public class HashCrossContextPsuedoSession<T> implements CrossContextPsuedoSession<T> -{ - private final String _cookieName; - - private final String _cookiePath; - - private final Random _random = new SecureRandom(); - - private final Map<String, T> _data = new HashMap<String, T>(); - - public HashCrossContextPsuedoSession(String cookieName, String cookiePath) - { - this._cookieName = cookieName; - this._cookiePath = cookiePath == null ? "/" : cookiePath; - } - - public T fetch(HttpServletRequest request) - { - Cookie[] cookies = request.getCookies(); - if (cookies == null) - return null; - - for (Cookie cookie : cookies) - { - if (_cookieName.equals(cookie.getName())) - { - String key = cookie.getValue(); - return _data.get(key); - } - } - return null; - } - - public void store(T datum, HttpServletResponse response) - { - String key; - - synchronized (_data) - { - // Create new ID - while (true) - { - key = Long.toString(Math.abs(_random.nextLong()), 30 + (int) (System.currentTimeMillis() % 7)); - if (!_data.containsKey(key)) break; - } - - _data.put(key, datum); - } - - Cookie cookie = new Cookie(_cookieName, key); - cookie.setPath(_cookiePath); - response.addCookie(cookie); - } - - public void clear(HttpServletRequest request) - { - for (Cookie cookie : request.getCookies()) - { - if (_cookieName.equals(cookie.getName())) - { - String key = cookie.getValue(); - _data.remove(key); - break; - } - } - } -} From 192e8e8ed144cff3c7004818a28bf39af139b96d Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 23 Jul 2014 16:54:05 +1000 Subject: [PATCH 150/269] expanded tabs in indents --- .../java/org/eclipse/jetty/server/HttpChannelOverHttp.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index d70b8d5f07c..b7efbe628e7 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -349,8 +349,8 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl @Override public void abort() { - super.abort(); - _generator.setPersistent(false); + super.abort(); + _generator.setPersistent(false); } @Override From 2f41275b0f705dde6398b8a98052880edb2eb1bf Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 23 Jul 2014 16:57:36 +1000 Subject: [PATCH 151/269] fixed merge syntax errors --- .../main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java | 2 +- .../src/main/java/org/eclipse/jetty/server/HttpConnection.java | 1 - .../org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index b7efbe628e7..fd60d3ebf67 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -350,7 +350,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl public void abort() { super.abort(); - _generator.setPersistent(false); + _httpConnection._generator.setPersistent(false); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 9ef44d783ca..d020d582484 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -450,7 +450,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _sendCallback.iterate(); } - super.abort(); private class SendCallback extends IteratingCallback { private ResponseInfo _info; diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java index 7090e22a06f..70a1651cdda 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java +++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java @@ -272,7 +272,6 @@ public class DecoderReaderTest } // TODO analyse and fix - @Ignore @Test @Ignore ("Quotes appear to be able to arrive in any order?") public void testTwoQuotes() throws Exception From 30123607c66627f74c8e8f7bed372f6e9b99ec31 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 24 Jul 2014 15:49:52 +1000 Subject: [PATCH 152/269] Major refactor of metadata and HttpURI This refactor strives to remove duplication between the Metadata class and the HttpURI class. Both classes have been made mutable (as they partially were anyway so best not to pretend). HttpURI now holds the decomposed strings rather than a single string with indexes. This allows it to be rebuilt after changing just parts of the URI. It is now a lot more similar to the JVM URI class and we could consider replacing it (after checking peformance). Next step is to refactor the Request class to prevent it duplicating these fields. --- .../fcgi/server/HttpChannelOverFCGI.java | 4 +- .../server/proxy/FastCGIProxyServlet.java | 1 + .../fcgi/server/proxy/TryFilesFilter.java | 1 + .../jetty/fcgi/server/EmptyServerHandler.java | 1 + .../jetty/fcgi/server/HttpClientTest.java | 1 + .../server/proxy/FastCGIProxyServletTest.java | 1 + .../fcgi/server/proxy/TryFilesFilterTest.java | 1 + .../WordPressSPDYFastCGIProxyServer.java | 1 + .../eclipse/jetty/http/AbstractMetaData.java | 163 ----- .../org/eclipse/jetty/http/FinalMetaData.java | 160 ----- .../org/eclipse/jetty/http/HttpFields.java | 5 +- .../java/org/eclipse/jetty/http/HttpURI.java | 637 ++++++++++-------- .../java/org/eclipse/jetty/http/MetaData.java | 295 +++++++- .../org/eclipse/jetty/http/HttpURITest.java | 99 +-- .../jetty/http2/client/AbstractTest.java | 3 +- .../jetty/http2/client/FlowControlTest.java | 11 +- .../jetty/http2/client/IdleTimeoutTest.java | 9 +- .../jetty/http2/client/StreamResetTest.java | 3 +- .../frames/HeadersGenerateParseTest.java | 11 +- .../frames/PushPromiseGenerateParseTest.java | 11 +- .../jetty/http2/hpack/AuthorityHttpField.java | 2 - .../jetty/http2/hpack/HpackDecoder.java | 1 - .../jetty/http2/hpack/HpackEncoder.java | 8 +- .../jetty/http2/hpack/MetaDataBuilder.java | 8 +- .../jetty/http2/hpack/HpackContextTest.java | 12 +- .../jetty/http2/hpack/HpackDecoderTest.java | 45 +- .../jetty/http2/hpack/HpackEncoderTest.java | 23 +- .../eclipse/jetty/http2/hpack/HpackTest.java | 9 +- .../jetty/http2/hpack/NBitIntegerTest.java | 4 +- .../http2/server/HttpChannelOverHTTP2.java | 2 +- .../http2/server/HttpTransportOverHTTP2.java | 3 +- .../jetty/http2/server/HTTP2ServerTest.java | 13 +- .../server/ForwardedRequestCustomizer.java | 22 +- .../jetty/server/HttpChannelOverHttp.java | 86 +-- .../org/eclipse/jetty/server/Request.java | 46 +- .../spdy/server/http/HttpChannelOverSPDY.java | 4 +- .../server/http/ReferrerPushStrategyTest.java | 9 +- .../server/proxy/ProxyHTTPToSPDYTest.java | 6 +- .../server/proxy/ProxySPDYToHTTPLoadTest.java | 11 +- .../server/proxy/ProxySPDYToHTTPTest.java | 11 +- .../server/proxy/ProxySPDYToSPDYLoadTest.java | 8 +- .../server/proxy/ProxySPDYToSPDYTest.java | 6 +- .../org/eclipse/jetty/util/UrlEncoded.java | 10 + 43 files changed, 825 insertions(+), 942 deletions(-) delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/AbstractMetaData.java delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java index df7afda8482..d99e709ffb7 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java @@ -23,13 +23,11 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.fcgi.FCGI; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; @@ -90,7 +88,7 @@ public class HttpChannelOverFCGI extends HttpChannel if (query != null && query.length() > 0) uri += "?" + query; // TODO https? - onRequest(new FinalMetaData.Request(HttpVersion.fromString(version), HttpScheme.HTTP.asString(), method, uri, fields, hostPort)); + onRequest(new MetaData.Request(method, HttpScheme.HTTP.asString(), hostPort, uri, HttpVersion.fromString(version), fields)); } private HttpField convertHeader(HttpField field) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java index b10beec9d86..3b1bb864d51 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java @@ -22,6 +22,7 @@ import java.net.URI; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; + import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletException; diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java index 2ce21643587..5e4e660c662 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java @@ -24,6 +24,7 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; + import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java index 7eaf4e2091e..9097da7ad66 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.fcgi.server; import java.io.IOException; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java index e97750f8b50..d0522dd6d57 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java @@ -32,6 +32,7 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.zip.GZIPOutputStream; + import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java index a52a044e956..7fe651ec27e 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Random; import java.util.concurrent.TimeUnit; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java index e1d78c79b44..9cd494dace8 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.fcgi.server.proxy; import java.io.IOException; import java.util.EnumSet; + import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressSPDYFastCGIProxyServer.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressSPDYFastCGIProxyServer.java index ea023a4b00a..7a52784e9d0 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressSPDYFastCGIProxyServer.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressSPDYFastCGIProxyServer.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.fcgi.server.proxy; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; + import javax.servlet.DispatcherType; import org.eclipse.jetty.server.Server; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractMetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractMetaData.java deleted file mode 100644 index 524e94b1113..00000000000 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractMetaData.java +++ /dev/null @@ -1,163 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - -import java.util.Iterator; - -public abstract class AbstractMetaData implements MetaData -{ - @Override - public boolean isRequest() - { - return false; - } - - @Override - public boolean isResponse() - { - return false; - } - - @Override - public Iterator<HttpField> iterator() - { - return getFields().iterator(); - } - - @Override - public int hashCode() - { - return 31 * getHttpVersion().hashCode() + getFields().hashCode(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (!(o instanceof AbstractMetaData)) - return false; - AbstractMetaData that = (AbstractMetaData)o; - - if (getHttpVersion() != that.getHttpVersion()) - return false; - - return getFields().equals(that.getFields()); - } - - @Override - public String toString() - { - StringBuilder out = new StringBuilder(); - for (HttpField field: this) - out.append(field).append(System.lineSeparator()); - return out.toString(); - } - - /* -------------------------------------------------------- */ - /* -------------------------------------------------------- */ - /* -------------------------------------------------------- */ - public abstract static class Request extends AbstractMetaData implements MetaData.Request - { - @Override - public boolean isRequest() - { - return true; - } - - @Override - public boolean isResponse() - { - return false; - } - - @Override - public int hashCode() - { - int hash = getMethod().hashCode(); - hash = 31 * hash + getScheme().hashCode(); - hash = 31 * hash + getURI().hashCode(); - return 31 * hash + super.hashCode(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (!(o instanceof MetaData.Request)) - return false; - MetaData.Request that = (MetaData.Request)o; - if (!getMethod().equals(that.getMethod()) || - !getScheme().equals(that.getScheme()) || - !getURI().equals(that.getURI())) - return false; - return super.equals(o); - } - - @Override - public String toString() - { - return String.format("%s %s://%s:%d%s HTTP/2%s%s", - getMethod(), getScheme(), getHost(), getPort(), getURI(), System.lineSeparator(), super.toString()); - } - } - - /* -------------------------------------------------------- */ - /* -------------------------------------------------------- */ - /* -------------------------------------------------------- */ - public abstract static class Response extends AbstractMetaData implements MetaData.Response - { - @Override - public boolean isRequest() - { - return false; - } - - @Override - public boolean isResponse() - { - return true; - } - @Override - public int hashCode() - { - return 31 * getStatus() + super.hashCode(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (!(o instanceof MetaData.Response)) - return false; - MetaData.Response that = (MetaData.Response)o; - if (getStatus() != that.getStatus()) - return false; - return super.equals(o); - } - - @Override - public String toString() - { - return String.format("HTTP/2 %d%s%s", getStatus(), System.lineSeparator(), super.toString()); - } - } -} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java deleted file mode 100644 index e3a2bac20f2..00000000000 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/FinalMetaData.java +++ /dev/null @@ -1,160 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http; - - -public class FinalMetaData extends AbstractMetaData -{ - private final HttpVersion _version; - private final HttpFields _fields; - - public FinalMetaData(HttpVersion version,HttpFields fields) - { - _fields=fields; - _version=version; - } - - @Override - public HttpVersion getHttpVersion() - { - return _version; - } - - @Override - public HttpFields getFields() - { - return _fields; - } - - - /* -------------------------------------------------------- */ - /* -------------------------------------------------------- */ - /* -------------------------------------------------------- */ - public static class Request extends AbstractMetaData.Request - { - private final HttpVersion _version; - private final HttpFields _fields; - private final String _method; - private final String _uri; - private final HostPortHttpField _hostPort; - private final HttpScheme _scheme; - - public Request(HttpVersion version, String scheme, String method, String uri, HttpFields fields, HostPortHttpField hostPort) - { - _fields=fields; - _version=version; - _method=method; - _uri=uri; - _hostPort = hostPort; - if (scheme == null) - _scheme = HttpScheme.HTTP; - else - { - HttpScheme s = HttpScheme.CACHE.get(scheme); - _scheme = s == null ? HttpScheme.HTTP : s; - } - } - - public Request(HttpVersion version, HttpScheme scheme, String method, HostPortHttpField authority, String path, HttpFields fields) - { - _fields=fields; - _version=version; - _method=method; - _uri=path; - _hostPort = authority; - _scheme=scheme; - } - - @Override - public HttpVersion getHttpVersion() - { - return _version; - } - - @Override - public HttpFields getFields() - { - return _fields; - } - - @Override - public String getMethod() - { - return _method; - } - - @Override - public HttpScheme getScheme() - { - return _scheme; - } - - @Override - public String getHost() - { - return _hostPort==null?null:_hostPort.getHost(); - } - - @Override - public int getPort() - { - return _hostPort==null?0:_hostPort.getPort(); - } - - @Override - public String getURI() - { - return _uri; - } - } - - /* -------------------------------------------------------- */ - /* -------------------------------------------------------- */ - /* -------------------------------------------------------- */ - public static class Response extends AbstractMetaData.Response - { - private final HttpVersion _version; - private final HttpFields _fields; - private final int _status; - - public Response(HttpVersion version, int status, HttpFields fields) - { - _fields=fields; - _version=version; - _status=status; - } - - @Override - public HttpVersion getHttpVersion() - { - return _version; - } - - @Override - public HttpFields getFields() - { - return _fields; - } - - public int getStatus() - { - return _status; - } - } -} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 978593a9f02..bdc251bdc38 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -564,7 +564,10 @@ public class HttpFields implements Iterable<HttpField> @Override public int hashCode() { - return _fields.hashCode(); + int hash=0; + for (HttpField field:_fields) + hash+=field.hashCode(); + return hash; } @Override diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index fc7cdb7d61d..f9c48a2f73f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http; import java.io.UnsupportedEncodingException; import java.net.URI; +import java.net.URISyntaxException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -50,297 +51,244 @@ import org.eclipse.jetty.util.UrlEncoded; */ public class HttpURI { - private final static int - START=0, - AUTH_OR_PATH=1, - SCHEME_OR_PATH=2, - AUTH=4, - IPV6=5, - PORT=6, - PATH=7, - PARAM=8, - QUERY=9, - ASTERISK=10; + private enum State { + START, + HOST_OR_PATH, + SCHEME_OR_PATH, + HOST, + IPV6, + PORT, + PATH, + PARAM, + QUERY, + FRAGMENT, + ASTERISK}; - boolean _partial=false; + private String _scheme; + private String _host; + private int _port; + private String _path; + private String _param; + private String _query; + private String _fragment; + String _uri; - int _scheme; - int _authority; - int _host; - int _port; - int _portValue; - int _path; - int _param; - int _query; - int _fragment; - int _end; - boolean _encoded=false; + String _decodedPath; + /* ------------------------------------------------------------ */ public HttpURI() { } /* ------------------------------------------------------------ */ - /** - * @param parsePartialAuth If True, parse auth without prior scheme, else treat all URIs starting with / as paths - */ - public HttpURI(boolean parsePartialAuth) - { - _partial=parsePartialAuth; - } - public HttpURI(String uri) { - _uri=uri; parse(uri); + parse(State.START,uri,0,uri.length()); } + /* ------------------------------------------------------------ */ public HttpURI(URI uri) { - this(uri.toASCIIString()); + _uri=null; + + _scheme=uri.getScheme(); + _host=uri.getHost(); + _port=uri.getPort(); + _path=uri.getRawPath(); + _decodedPath=uri.getPath(); + int p=_path.lastIndexOf(';'); + if (p>=0) + _param=_path.substring(p+1); + _query=uri.getRawQuery(); + _fragment=uri.getFragment(); + + _decodedPath=null; } - - public void parseConnect(String authority) + /* ------------------------------------------------------------ */ + public HttpURI(String scheme, String host, int port, String pathQuery) { - parseConnect(authority,0,authority.length()); + _uri=null; + + _scheme=scheme; + _host=host; + _port=port; + + parse(State.PATH,pathQuery,0,pathQuery.length()); + } - - public void parseConnect(String authority,int offset,int length) - { - _uri=authority; - _encoded=false; - int i=offset; - int e=offset+length; - int state=AUTH; - _end=offset+length; - _scheme=offset; - _authority=offset; - _host=offset; - _port=_end; - _portValue=-1; - _path=_end; - _param=_end; - _query=_end; - _fragment=_end; - loop: while (i<e) + /* ------------------------------------------------------------ */ + public void parse(String uri) + { + clear(); + _uri=uri; + parse(State.START,uri,0,uri.length()); + } + + /* ------------------------------------------------------------ */ + public void parse(String uri, int offset, int length) + { + clear(); + int end=offset+length; + _uri=uri.substring(offset,end); + parse(State.START,uri,offset,end); + } + + /* ------------------------------------------------------------ */ + private void parse(State state, final String uri, final int offset, final int end) + { + boolean encoded=false; + int m=offset; + int p=0; + + for (int i=offset; i<end; i++) { - char c=authority.charAt(i); - int s=i++; + char c=uri.charAt(i); switch (state) - { - case AUTH: - { - switch (c) - { - case ':': - { - _port = s; - break loop; - } - case '[': - { - state = IPV6; - break; - } - } - continue; - } - - case IPV6: - { - switch (c) - { - case '/': - { - throw new IllegalArgumentException("No closing ']' for " + _uri.substring(offset,length)); - } - case ']': - { - state = AUTH; - break; - } - } - - continue; - } - } - } - - if (_port<_path) - _portValue=TypeUtil.parseInt(_uri, _port+1, _path-_port-1,10); - else - throw new IllegalArgumentException("No port"); - _path=offset; - } - - - public void parse(String uri) - { - _uri=uri; - _encoded=false; - int i=0; - int e=uri.length(); - int state=START; - int m=i; - _end=e; - _scheme=i; - _authority=i; - _host=i; - _port=i; - _portValue=-1; - _path=i; - _param=_end; - _query=_end; - _fragment=_end; - while (i<e) - { - char c=uri.charAt(i); - int s=i++; - - state: switch (state) { case START: { - m=s; switch(c) { case '/': - state=AUTH_OR_PATH; + p=m=i; + state=State.PATH; break; case ';': - _param=s; - state=PARAM; + m=i+1; + state=State.PARAM; break; case '?': - _param=s; - _query=s; - state=QUERY; + m=i+1; + state=State.QUERY; break; case '#': - _param=s; - _query=s; - _fragment=s; + m=i+1; + state=State.FRAGMENT; break; case '*': - _path=s; - state=ASTERISK; + _path="*"; + state=State.ASTERISK; break; default: - state=SCHEME_OR_PATH; + m=i; + state=State.SCHEME_OR_PATH; } continue; } - case AUTH_OR_PATH: - { - if ((_partial||_scheme!=_authority) && c=='/') - { - _host=i; - _port=_end; - _path=_end; - state=AUTH; - } - else if (c==';' || c=='?' || c=='#') - { - i--; - state=PATH; - } - else - { - _host=m; - _port=m; - state=PATH; - } - continue; - } - case SCHEME_OR_PATH: { switch (c) { case ':': { - m = i++; - _authority = m; - _path = m; - c = uri.charAt(i); + // must have been a scheme + _scheme=uri.substring(m,i); + c = uri.charAt(++i); + m=i; if (c == '/') - state = AUTH_OR_PATH; + state=State.HOST_OR_PATH; else - { - _host = m; - _port = m; - state = PATH; - } + state=State.PATH; break; } case '/': { - state = PATH; + // must have been in a path and still are + state=State.PATH; break; } case ';': { - _param = s; - state = PARAM; + // must have been in a path + p=m; + state=State.PARAM; break; } case '?': { - _param = s; - _query = s; - state = QUERY; + // must have been in a path + _path=uri.substring(m,i); + state=State.QUERY; break; } - case '#': + case '%': { - _param = s; - _query = s; - _fragment = s; - break; + encoded=true; } - + case '#': + { + // must have been in a path + _path=uri.substring(m,i); + state=State.FRAGMENT; + break; + } + } + continue; + } + + case HOST_OR_PATH: + { + switch(c) + { + case '/': + m=i+1; + state=State.HOST; + break; + + case ';': + case '?': + case '#': + // was a path, look again + i--; + p=m; + state=State.PATH; + break; + default: + // it is a path + p=m; + state=State.PATH; } continue; } - case AUTH: + case HOST: { switch (c) { - case '/': { - m = s; - _path = m; - _port = _path; - state = PATH; - break; - } - case '@': - { - _host = i; + _host=uri.substring(m,i); + p=m=i; + state=State.PATH; break; } case ':': { - _port = s; - state = PORT; + _host=uri.substring(m,i); + m=i+1; + state=State.PORT; break; } + case '@': + // ignore user + m=i+1; + break; + case '[': { - state = IPV6; + state=State.IPV6; break; } } @@ -357,7 +305,18 @@ public class HttpURI } case ']': { - state = AUTH; + c = uri.charAt(++i); + _host=uri.substring(m,i); + if (c == ':') + { + m=i+1; + state=State.PORT; + } + else + { + p=m=i; + state=State.PATH; + } break; } } @@ -369,11 +328,9 @@ public class HttpURI { if (c=='/') { - m=s; - _path=m; - if (_port<=_authority) - _port=_path; - state=PATH; + _port=TypeUtil.parseInt(uri,m,i-m,10); + p=m=i; + state=State.PATH; } continue; } @@ -384,27 +341,27 @@ public class HttpURI { case ';': { - _param = s; - state = PARAM; + m=i+1; + state=State.PARAM; break; } case '?': { - _param = s; - _query = s; - state = QUERY; + _path=uri.substring(p,i); + m=i+1; + state=State.QUERY; break; } case '#': { - _param = s; - _query = s; - _fragment = s; - break state; + _path=uri.substring(p,i); + m=i+1; + state=State.FRAGMENT; + break; } case '%': { - _encoded=true; + encoded=true; } } continue; @@ -416,20 +373,26 @@ public class HttpURI { case '?': { - _query = s; - state = QUERY; + _path=uri.substring(p,i); + _param=uri.substring(m,i); + m=i+1; + state=State.QUERY; break; } case '#': { - _query = s; - _fragment = s; - break state; + _path=uri.substring(p,i); + _param=uri.substring(m,i); + m=i+1; + state=State.FRAGMENT; + break; } case '/': { - state=PATH; - break state; + encoded=true; + // ignore internal params + state=State.PATH; + break; } } continue; @@ -439,8 +402,9 @@ public class HttpURI { if (c=='#') { - _fragment=s; - break state; + _query=uri.substring(m,i); + m=i+1; + state=State.FRAGMENT; } continue; } @@ -449,138 +413,208 @@ public class HttpURI { throw new IllegalArgumentException("only '*'"); } + + case FRAGMENT: + { + _fragment=uri.substring(m,end); + i=end; + } } } - if (_port<_path) - _portValue=TypeUtil.parseInt(_uri, _port+1, _path-_port-1,10); + + switch(state) + { + case START: + break; + case SCHEME_OR_PATH: + _path=uri.substring(m,end); + break; + + case HOST_OR_PATH: + _path=uri.substring(m,end); + break; + + case HOST: + _host=uri.substring(m,end); + break; + + case IPV6: + throw new IllegalArgumentException("No closing ']' for ipv6 in " + uri); + + case PORT: + _port=TypeUtil.parseInt(uri,m,end-m,10); + break; + + case ASTERISK: + break; + + case FRAGMENT: + _fragment=uri.substring(m,end); + break; + + case PARAM: + _path=uri.substring(p,end); + _param=uri.substring(m,end); + break; + + case PATH: + _path=uri.substring(p,end); + break; + + case QUERY: + _query=uri.substring(m,end); + break; + } + + if (!encoded) + { + if (_param==null) + _decodedPath=_path; + else + _decodedPath=_path.substring(0,_path.length()-_param.length()-1); + } } + /* ------------------------------------------------------------ */ public String getScheme() { - if (_scheme==_authority) - return null; - int l=_authority-_scheme; - if (l==5 && _uri.startsWith("http:")) - return HttpScheme.HTTP.asString(); - if (l==6 && _uri.startsWith("https:")) - return HttpScheme.HTTPS.asString(); - - return _uri.substring(_scheme,_authority-_scheme-1); - } - - public String getAuthority() - { - if (_authority==_path) - return null; - return _uri.substring(_authority,_path); + return _scheme; } + /* ------------------------------------------------------------ */ public String getHost() { - if (_host==_port) - return null; - return _uri.substring(_host,_port); + return _host; } + /* ------------------------------------------------------------ */ public int getPort() { - return _portValue; + return _port; } + /* ------------------------------------------------------------ */ public String getPath() { - if (_path==_query) - return null; - return _uri.substring(_path,_query); + return _path; } + /* ------------------------------------------------------------ */ public String getDecodedPath() { - if (_path==_query) - return null; - return URIUtil.decodePath(_uri,_path,_query-_path); - } - - public String getPathAndParam() - { - if (_path==_query) - return null; - return _uri.substring(_path,_query); - } - - public String getCompletePath() - { - if (_path==_end) - return null; - return _uri.substring(_path,_end); + if (_decodedPath==null && _path!=null) + _decodedPath=URIUtil.decodePath(_path); + return _decodedPath; } + /* ------------------------------------------------------------ */ public String getParam() { - if (_param==_query) - return null; - return _uri.substring(_param+1,_query); + return _param; } + /* ------------------------------------------------------------ */ public String getQuery() { - if (_query==_fragment) - return null; - return _uri.substring(_query+1,_fragment); + return _query; } + /* ------------------------------------------------------------ */ public boolean hasQuery() { - return (_fragment>_query); + return _query!=null && _query.length()>0; } + /* ------------------------------------------------------------ */ public String getFragment() { - if (_fragment==_end) - return null; - - return _uri.substring(_fragment+1,_end); + return _fragment; } + /* ------------------------------------------------------------ */ public void decodeQueryTo(MultiMap<String> parameters) { if (_query==_fragment) return; - UrlEncoded.decodeUtf8To(_uri,_query+1,_fragment-_query-1,parameters); + UrlEncoded.decodeUtf8To(_query,parameters); } + /* ------------------------------------------------------------ */ public void decodeQueryTo(MultiMap<String> parameters, String encoding) throws UnsupportedEncodingException { - if (_query==_fragment) - return; decodeQueryTo(parameters,Charset.forName(encoding)); } + /* ------------------------------------------------------------ */ public void decodeQueryTo(MultiMap<String> parameters, Charset encoding) throws UnsupportedEncodingException { if (_query==_fragment) return; if (encoding==null || StandardCharsets.UTF_8.equals(encoding)) - UrlEncoded.decodeUtf8To(_uri,_query+1,_fragment-_query-1,parameters); + UrlEncoded.decodeUtf8To(_query,parameters); else - UrlEncoded.decodeTo(_uri.substring(_query+1,_fragment-_query-1),parameters,encoding); + UrlEncoded.decodeTo(_query,parameters,encoding); } + /* ------------------------------------------------------------ */ public void clear() { - _scheme=_authority=_host=_port=_path=_param=_query=_fragment=_end=0; _uri=null; - _encoded=false; + + _scheme=null; + _host=null; + _port=-1; + _path=null; + _param=null; + _query=null; + _fragment=null; + + _decodedPath=null; } + /* ------------------------------------------------------------ */ + public boolean isAbsolute() + { + return _scheme!=null && _scheme.length()>0; + } + + /* ------------------------------------------------------------ */ @Override public String toString() { + if (_uri==null) + { + StringBuilder out = new StringBuilder(); + + if (_scheme!=null) + out.append(_scheme).append(':'); + + if (_host!=null) + out.append("//").append(_host); + + if (_port>0) + out.append(':').append(_port); + + if (_path!=null) + out.append(_path); + + if (_query!=null) + out.append('?').append(_query); + + if (_fragment!=null) + out.append('#').append(_fragment); + + if (out.length()>0) + _uri=out.toString(); + else + _uri=""; + } return _uri; } + /* ------------------------------------------------------------ */ public boolean equals(Object o) { if (o==this) @@ -590,4 +624,37 @@ public class HttpURI return toString().equals(o.toString()); } + /* ------------------------------------------------------------ */ + /** + * @param host + * @param port + */ + public void setAuth(String host, int port) + { + _host=host; + _port=port; + _uri=null; + } + + /* ------------------------------------------------------------ */ + public URI toURI() throws URISyntaxException + { + return new URI(_scheme,null,_host,_port,_path,_query==null?null:UrlEncoded.decodeString(_query),_fragment); + } + + /* ------------------------------------------------------------ */ + public String getPathQuery() + { + if (_query==null) + return _path; + return _path+"?"+_query; + } + + /* ------------------------------------------------------------ */ + public String getAuthority() + { + if (_port>0) + return _host+":"+_port; + return _host; + } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index 4bf47ab3793..30405fe92b6 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -18,30 +18,299 @@ package org.eclipse.jetty.http; -public interface MetaData extends Iterable<HttpField> +import java.util.Iterator; + +public class MetaData implements Iterable<HttpField> { - public HttpVersion getHttpVersion(); - public boolean isRequest(); - public boolean isResponse(); - public HttpFields getFields(); + private HttpVersion _httpVersion; + private HttpFields _fields; + + /* ------------------------------------------------------------ */ + public MetaData() + { + } + + /* ------------------------------------------------------------ */ + public MetaData(HttpVersion version, HttpFields fields) + { + _httpVersion = version; + _fields = fields; + } + + /* ------------------------------------------------------------ */ + public boolean isRequest() + { + return false; + } + + /* ------------------------------------------------------------ */ + public boolean isResponse() + { + return false; + } + + /* ------------------------------------------------------------ */ + /** Get the httpVersion. + * @return the httpVersion + */ + public HttpVersion getVersion() + { + return _httpVersion; + } + + /* ------------------------------------------------------------ */ + /** Set the httpVersion. + * @param httpVersion the httpVersion to set + */ + public void setHttpVersion(HttpVersion httpVersion) + { + _httpVersion = httpVersion; + } + + /* ------------------------------------------------------------ */ + /** Get the fields. + * @return the fields + */ + public HttpFields getFields() + { + return _fields; + } + + /* ------------------------------------------------------------ */ + /** Set the fields. + * @param fields the fields to set + */ + public void setFields(HttpFields fields) + { + _fields = fields; + } + + /* ------------------------------------------------------------ */ + public Iterator<HttpField> iterator() + { + return getFields().iterator(); + } + + /* ------------------------------------------------------------ */ + @Override + public int hashCode() + { + return 31 * getVersion().hashCode() + getFields().hashCode(); + } + + /* ------------------------------------------------------------ */ + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof MetaData)) + return false; + MetaData that = (MetaData)o; + + if (getVersion() != that.getVersion()) + return false; + + return getFields().equals(that.getFields()); + } + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + StringBuilder out = new StringBuilder(); + for (HttpField field: this) + out.append(field).append(System.lineSeparator()); + return out.toString(); + } /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ - public interface Request extends MetaData + public static class Request extends MetaData { - public String getMethod(); - public HttpScheme getScheme(); - public String getHost(); - public int getPort(); - public String getURI(); + private String _method; + private HttpURI _uri; + + public Request() + { + } + + /* ------------------------------------------------------------ */ + /** + * @param method + * @param uri + * @param version + * @param fields + */ + public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields) + { + super(version,fields); + _method = method; + _uri = uri; + } + + /* ------------------------------------------------------------ */ + public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields) + { + this(method,new HttpURI(scheme==null?null:scheme.asString(),hostPort.getHost(),hostPort.getPort(),uri),version,fields); + } + + /* ------------------------------------------------------------ */ + public Request(String method, String scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields) + { + this(method,new HttpURI(scheme,hostPort.getHost(),hostPort.getPort(),uri),version,fields); + } + + /* ------------------------------------------------------------ */ + @Override + public boolean isRequest() + { + return true; + } + + /* ------------------------------------------------------------ */ + /** Get the method. + * @return the method + */ + public String getMethod() + { + return _method; + } + + /* ------------------------------------------------------------ */ + /** Set the method. + * @param method the method to set + */ + public void setMethod(String method) + { + _method = method; + } + + /* ------------------------------------------------------------ */ + /** Get the uri. + * @return the uri + */ + public HttpURI getURI() + { + return _uri; + } + + /* ------------------------------------------------------------ */ + /** Set the uri. + * @param uri the uri to set + */ + public void setURI(HttpURI uri) + { + _uri = uri; + } + + /* ------------------------------------------------------------ */ + @Override + public int hashCode() + { + return ((super.hashCode()*31)+_method.hashCode())*31+_uri.hashCode(); + } + + /* ------------------------------------------------------------ */ + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof MetaData.Request)) + return false; + MetaData.Request that = (MetaData.Request)o; + if (!getMethod().equals(that.getMethod()) || + !getURI().equals(that.getURI())) + return false; + return super.equals(o); + } + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + return String.format("%s %s %s%s%s", + getMethod(), getURI(), getVersion(), System.lineSeparator(), super.toString()); + } } /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ - public interface Response extends MetaData + public static class Response extends MetaData { - public int getStatus(); + private int _status; + + public Response() + { + } + + /* ------------------------------------------------------------ */ + /** + * @param version + * @param fields + * @param status + */ + public Response(HttpVersion version, int status, HttpFields fields) + { + super(version,fields); + _status=status; + } + + /* ------------------------------------------------------------ */ + @Override + public boolean isResponse() + { + return true; + } + + /* ------------------------------------------------------------ */ + /** Get the status. + * @return the status + */ + public int getStatus() + { + return _status; + } + + /* ------------------------------------------------------------ */ + /** Set the status. + * @param status the status to set + */ + public void setStatus(int status) + { + _status = status; + } + + /* ------------------------------------------------------------ */ + @Override + public int hashCode() + { + return 31 * getStatus() + super.hashCode(); + } + + /* ------------------------------------------------------------ */ + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof MetaData.Response)) + return false; + MetaData.Response that = (MetaData.Response)o; + if (getStatus() != that.getStatus()) + return false; + return super.equals(o); + } + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + return String.format("%s %d%s%s",getVersion(), getStatus(), System.lineSeparator(), super.toString()); + } + } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java index b5502fd9f96..1557a8425ff 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.http; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -75,7 +74,8 @@ public class HttpURITest { for (String[] test:tests) { - HttpURI uri = new HttpURI(new URI(test[INPUT])); + URI u=new URI(test[INPUT]); + HttpURI uri = new HttpURI(u); assertEquals(test[SCHEME], uri.getScheme()); assertEquals(test[HOST], uri.getHost()); @@ -84,67 +84,11 @@ public class HttpURITest assertEquals(test[PARAM], uri.getParam()); assertEquals(test[QUERY], uri.getQuery()); assertEquals(test[FRAGMENT], uri.getFragment()); + + assertEquals(u,uri.toURI()); } } - private final String[][] partial_tests= - { - /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, - /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, - /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, - /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, - /* 4*/ {"/path/info;param",null,null,null,null,"/path/info;param","param",null,null}, - /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info;param","param",null,"fragment"}, - /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info;param","param","query",null}, - /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info;param","param","query","fragment"}, - /* 8*/ {"//host/path/info",null,"//host","host",null,"/path/info",null,null,null}, - /* 9*/ {"//user@host/path/info",null,"//user@host","host",null,"/path/info",null,null,null}, - /*10*/ {"//user@host:8080/path/info",null,"//user@host:8080","host","8080","/path/info",null,null,null}, - /*11*/ {"//host:8080/path/info",null,"//host:8080","host","8080","/path/info",null,null,null}, - /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, - /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, - /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, - /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, - /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info;param","param",null,null}, - /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info;param","param",null,"fragment"}, - /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info;param","param","query",null}, - /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info;param","param","query","fragment"}, - /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info;param","param","query","fragment"}, - /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info;param","param","query","fragment"}, - /*22*/ {"http:///;?#","http","//",null,null,"/;","","",""}, - /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, - /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, - /*25*/ {"//host:8080//",null,"//host:8080","host","8080","//",null,null,null}, - /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, - /*27*/ {"//",null,"//",null,null,null,null,null,null}, - /*28*/ {"/;param",null, null, null,null,"/;param", "param",null,null}, - /*29*/ {"/?x=y",null, null, null,null,"/", null,"x=y",null}, - /*30*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null}, - /*31*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"}, - /*32*/ {"http://localhost:8080", "http", "//localhost:8080", "localhost", "8080", null, null, null, null}, - /*33*/ {"./?foo:bar=:1:1::::",null,null,null,null,"./",null,"foo:bar=:1:1::::",null} - }; - - @Test - public void testPartialURIs() throws Exception - { - HttpURI uri = new HttpURI(true); - - for (int t=0;t<partial_tests.length;t++) - { - uri.parse(partial_tests[t][0]); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][1],uri.getScheme()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][2],uri.getAuthority()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][3],uri.getHost()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][4]==null?-1:Integer.parseInt(partial_tests[t][4]),uri.getPort()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][5],uri.getPath()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][6],uri.getParam()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][7],uri.getQuery()); - assertEquals(t+" "+partial_tests[t][0],partial_tests[t][8],uri.getFragment()); - assertEquals(partial_tests[t][0], uri.toString()); - } - - } private final String[][] path_tests= { @@ -170,11 +114,11 @@ public class HttpURITest /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info;param","param","query","fragment"}, /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info;param","param","query","fragment"}, /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info;param","param","query","fragment"}, - /*22*/ {"http:///;?#","http","//",null,null,"/;","","",""}, + /*22*/ {"http:///;?#","http","//","",null,"/;","","",""}, /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, /*25*/ {"//host:8080//",null,null,null,null,"//host:8080//",null,null,null}, - /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, + /*26*/ {"file:///path/info","file","//","",null,"/path/info",null,null,null}, /*27*/ {"//",null,null,null,null,"//",null,null,null}, /*28*/ {"http://localhost/","http","//localhost","localhost",null,"/",null,null,null}, /*29*/ {"http://localhost:8080/", "http", "//localhost:8080", "localhost","8080","/", null, null,null}, @@ -201,7 +145,6 @@ public class HttpURITest { uri.parse(path_tests[t][0]); assertEquals(t+" "+path_tests[t][0],path_tests[t][1],uri.getScheme()); - assertEquals(t+" "+path_tests[t][0],path_tests[t][2],uri.getAuthority()); assertEquals(t+" "+path_tests[t][0],path_tests[t][3],uri.getHost()); assertEquals(t+" "+path_tests[t][0],path_tests[t][4]==null?-1:Integer.parseInt(path_tests[t][4]),uri.getPort()); assertEquals(t+" "+path_tests[t][0],path_tests[t][5],uri.getPath()); @@ -272,36 +215,6 @@ public class HttpURITest assertEquals(value,parameters.getString("value")); } } - - - private final String[][] connect_tests= - { - /* 0*/ {"localhost:8080","localhost","8080"}, - /* 1*/ {"127.0.0.1:8080","127.0.0.1","8080"}, - /* 2*/ {"[127::0::0::1]:8080","[127::0::0::1]","8080"}, - /* 3*/ {"error",null,null}, - /* 4*/ {"http://localhost:8080/",null,null}, - }; - - @Test - public void testCONNECT() throws Exception - { - HttpURI uri = new HttpURI(); - for (int i=0;i<connect_tests.length;i++) - { - try - { - uri.parseConnect(connect_tests[i][0]); - assertEquals("path"+i,connect_tests[i][0].trim(),uri.getPath()); - assertEquals("host"+i,connect_tests[i][1],uri.getHost()); - assertEquals("port"+i,Integer.parseInt(connect_tests[i][2]),uri.getPort()); - } - catch(Exception e) - { - assertNull("error"+i,connect_tests[i][1]); - } - } - } @Test diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java index 18485215f1d..ab9357ed8f8 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServlet; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; @@ -109,6 +108,6 @@ public class AbstractTest String host = "localhost"; int port = connector.getLocalPort(); String authority = host + ":" + port; - return new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, method, new HostPortHttpField(authority), path, fields); + return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields); } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index 186e0c97a3f..def59646e98 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -29,7 +29,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -73,7 +72,7 @@ public class FlowControlTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { HttpFields fields = new HttpFields(); - MetaData.Response response = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, fields); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, fields); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -151,7 +150,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); @@ -243,7 +242,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return new Stream.Listener.Adapter() @@ -348,7 +347,7 @@ public class FlowControlTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { // For every stream, send down half the window size of data. - MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(windowSize / 2), true); @@ -430,7 +429,7 @@ public class FlowControlTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.wrap(data), true); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java index ea3a8caa5ec..b05b6dd32bb 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java @@ -30,7 +30,6 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -62,7 +61,7 @@ public class IdleTimeoutTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { stream.setIdleTimeout(10 * idleTimeout); - MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return null; @@ -145,7 +144,7 @@ public class IdleTimeoutTest extends AbstractTest { stream.setIdleTimeout(10 * idleTimeout); Thread.sleep(2 * idleTimeout); - MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return null; @@ -204,7 +203,7 @@ public class IdleTimeoutTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { stream.setIdleTimeout(10 * idleTimeout); - MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return null; @@ -279,7 +278,7 @@ public class IdleTimeoutTest extends AbstractTest public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { stream.setIdleTimeout(10 * idleTimeout); - MetaData.Response metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return null; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java index 17fe58b821f..2bc87b45a08 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java @@ -23,7 +23,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -100,7 +99,7 @@ public class StreamResetTest extends AbstractTest @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - MetaData.Response response = new FinalMetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, false); stream.headers(responseFrame, Callback.Adapter.INSTANCE); return new Stream.Listener.Adapter() diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 09c66937df9..19a71134d52 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -22,7 +22,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -51,7 +50,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); + MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields); final List<HeadersFrame> frames = new ArrayList<>(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() @@ -84,10 +83,7 @@ public class HeadersGenerateParseTest Assert.assertEquals(streamId, frame.getStreamId()); Assert.assertTrue(frame.isEndStream()); MetaData.Request request = (MetaData.Request)frame.getMetaData(); - Assert.assertSame(metaData.getScheme(), request.getScheme()); Assert.assertEquals(metaData.getMethod(), request.getMethod()); - Assert.assertEquals(metaData.getHost(), request.getHost()); - Assert.assertEquals(metaData.getPort(), request.getPort()); Assert.assertEquals(metaData.getURI(), request.getURI()); for (int j = 0; j < fields.size(); ++j) { @@ -117,7 +113,7 @@ public class HeadersGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); + MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateHeaders(lease, streamId, metaData, false); @@ -135,10 +131,7 @@ public class HeadersGenerateParseTest Assert.assertEquals(streamId, frame.getStreamId()); Assert.assertTrue(frame.isEndStream()); MetaData.Request request = (MetaData.Request)frame.getMetaData(); - Assert.assertSame(metaData.getScheme(), request.getScheme()); Assert.assertEquals(metaData.getMethod(), request.getMethod()); - Assert.assertEquals(metaData.getHost(), request.getHost()); - Assert.assertEquals(metaData.getPort(), request.getPort()); Assert.assertEquals(metaData.getURI(), request.getURI()); for (int j = 0; j < fields.size(); ++j) { diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index b8a7827a889..b636086ef8f 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -22,7 +22,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -63,7 +62,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); + MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) @@ -85,10 +84,7 @@ public class PushPromiseGenerateParseTest Assert.assertEquals(streamId, frame.getStreamId()); Assert.assertEquals(promisedStreamId, frame.getPromisedStreamId()); MetaData.Request request = (MetaData.Request)frame.getMetaData(); - Assert.assertSame(metaData.getScheme(), request.getScheme()); Assert.assertEquals(metaData.getMethod(), request.getMethod()); - Assert.assertEquals(metaData.getHost(), request.getHost()); - Assert.assertEquals(metaData.getPort(), request.getPort()); Assert.assertEquals(metaData.getURI(), request.getURI()); for (int j = 0; j < fields.size(); ++j) { @@ -119,7 +115,7 @@ public class PushPromiseGenerateParseTest HttpFields fields = new HttpFields(); fields.put("Accept", "text/html"); fields.put("User-Agent", "Jetty"); - MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, "GET", new HostPortHttpField("localhost:8080"), "/path", fields); + MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generatePushPromise(lease, streamId, promisedStreamId, metaData); @@ -137,10 +133,7 @@ public class PushPromiseGenerateParseTest Assert.assertEquals(streamId, frame.getStreamId()); Assert.assertEquals(promisedStreamId, frame.getPromisedStreamId()); MetaData.Request request = (MetaData.Request)frame.getMetaData(); - Assert.assertSame(metaData.getScheme(), request.getScheme()); Assert.assertEquals(metaData.getMethod(), request.getMethod()); - Assert.assertEquals(metaData.getHost(), request.getHost()); - Assert.assertEquals(metaData.getPort(), request.getPort()); Assert.assertEquals(metaData.getURI(), request.getURI()); for (int j = 0; j < fields.size(); ++j) { diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java index 99bdf14593d..a0672d122a4 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java @@ -20,8 +20,6 @@ package org.eclipse.jetty.http2.hpack; import org.eclipse.jetty.http.HostPortHttpField; -import org.eclipse.jetty.http2.hpack.HpackContext; -import org.eclipse.jetty.util.StringUtil; /* ------------------------------------------------------------ */ diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index ff376a57678..4e960289dfa 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -27,7 +27,6 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.TypeUtil; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 78ac879f74f..e30566ea3cf 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -24,6 +24,7 @@ import java.util.EnumSet; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; @@ -139,10 +140,11 @@ public class HpackEncoder MetaData.Request request = (MetaData.Request)metadata; // TODO optimise these to avoid HttpField creation - encode(buffer,new HttpField(":scheme",request.getScheme().asString())); + String scheme=request.getURI().getScheme(); + encode(buffer,new HttpField(":scheme",scheme==null?HttpScheme.HTTP.asString():scheme)); encode(buffer,new HttpField(":method",request.getMethod())); - encode(buffer,new HttpField(":authority",request.getPort()>0?(request.getHost()+':'+request.getPort()):request.getHost())); - encode(buffer,new HttpField(":path",request.getURI())); + encode(buffer,new HttpField(":authority",request.getURI().getAuthority())); + encode(buffer,new HttpField(":path",request.getURI().getPathQuery())); } else if (metadata.isResponse()) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index aa09a31f80f..b7793bc1e92 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -21,13 +21,11 @@ package org.eclipse.jetty.http2.hpack; import org.eclipse.jetty.http.BadMessageException; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -133,10 +131,10 @@ public class MetaDataBuilder HttpFields fields = _fields; _fields = new HttpFields(Math.max(10,fields.size()+5)); if (_method!=null) - return new FinalMetaData.Request(HttpVersion.HTTP_2,_scheme,_method,_authority,_path,fields); + return new MetaData.Request(_method,_scheme,_authority,_path,HttpVersion.HTTP_2,fields); if (_status!=0) - return new FinalMetaData.Response(HttpVersion.HTTP_2,_status,fields); - return new FinalMetaData(HttpVersion.HTTP_2,fields); + return new MetaData.Response(HttpVersion.HTTP_2,_status,fields); + return new MetaData(HttpVersion.HTTP_2,fields); } finally { diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java index 46a5cdc7803..9809b81c2d2 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java @@ -20,6 +20,12 @@ package org.eclipse.jetty.http2.hpack; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.nio.ByteBuffer; import java.util.HashSet; import java.util.Iterator; @@ -31,12 +37,6 @@ import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - /* ------------------------------------------------------------ */ /** diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index d3966d79012..14501a81248 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -19,20 +19,19 @@ package org.eclipse.jetty.http2.hpack; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.nio.ByteBuffer; import java.util.Iterator; import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.util.TypeUtil; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - /* ------------------------------------------------------------ */ /** @@ -52,9 +51,9 @@ public class HpackDecoderTest MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getURI()); - assertEquals("www.example.com",request.getHost()); + assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); + assertEquals("/",request.getURI().getPath()); + assertEquals("www.example.com",request.getURI().getHost()); assertFalse(request.iterator().hasNext()); @@ -65,9 +64,9 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getURI()); - assertEquals("www.example.com",request.getHost()); + assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); + assertEquals("/",request.getURI().getPath()); + assertEquals("www.example.com",request.getURI().getHost()); Iterator<HttpField> iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); @@ -81,9 +80,9 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET",request.getMethod()); - assertEquals(HttpScheme.HTTPS,request.getScheme()); - assertEquals("/index.html",request.getURI()); - assertEquals("www.example.com",request.getHost()); + assertEquals(HttpScheme.HTTPS.asString(),request.getURI().getScheme()); + assertEquals("/index.html",request.getURI().getPath()); + assertEquals("www.example.com",request.getURI().getHost()); iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); @@ -102,9 +101,9 @@ public class HpackDecoderTest MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getURI()); - assertEquals("www.example.com",request.getHost()); + assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); + assertEquals("/",request.getURI().getPath()); + assertEquals("www.example.com",request.getURI().getHost()); assertFalse(request.iterator().hasNext()); @@ -115,9 +114,9 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP,request.getScheme()); - assertEquals("/",request.getURI()); - assertEquals("www.example.com",request.getHost()); + assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); + assertEquals("/",request.getURI().getPath()); + assertEquals("www.example.com",request.getURI().getHost()); Iterator<HttpField> iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); @@ -130,9 +129,9 @@ public class HpackDecoderTest request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET",request.getMethod()); - assertEquals(HttpScheme.HTTPS,request.getScheme()); - assertEquals("/index.html",request.getURI()); - assertEquals("www.example.com",request.getHost()); + assertEquals(HttpScheme.HTTPS.asString(),request.getURI().getScheme()); + assertEquals("/index.html",request.getURI().getPath()); + assertEquals("www.example.com",request.getURI().getHost()); iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index 8286ab345c3..61b52a947f4 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -20,10 +20,11 @@ package org.eclipse.jetty.http2.hpack; +import static org.junit.Assert.assertThat; + import java.nio.ByteBuffer; import java.util.HashSet; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; @@ -34,8 +35,6 @@ import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.assertThat; - /* ------------------------------------------------------------ */ /** @@ -71,7 +70,7 @@ public class HpackEncoderTest // encode them ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,pos); // something was encoded! @@ -90,7 +89,7 @@ public class HpackEncoderTest // encode exact same fields again! BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // nothing should be encoded! @@ -113,7 +112,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -137,7 +136,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -164,7 +163,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -192,7 +191,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -226,7 +225,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -247,7 +246,7 @@ public class HpackEncoderTest // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! @@ -259,7 +258,7 @@ public class HpackEncoderTest // encode again BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index 4323ca8d7c8..ac6a9ac7568 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertEquals; import java.nio.ByteBuffer; import org.eclipse.jetty.http.BadMessageException; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; @@ -51,7 +50,7 @@ public class HpackTest fields0.add(HttpHeader.SERVER,"jetty"); fields0.add(HttpHeader.SET_COOKIE,"abcdefghijklmnopqrstuvwxyz"); fields0.add("custom-key","custom-value"); - Response original0 = new FinalMetaData.Response(HttpVersion.HTTP_2,200,fields0); + Response original0 = new MetaData.Response(HttpVersion.HTTP_2,200,fields0); BufferUtil.clearToFill(buffer); encoder.encode(buffer,original0); @@ -73,7 +72,7 @@ public class HpackTest fields1.add(HttpHeader.CONTENT_LENGTH,"1234"); fields1.add(HttpHeader.SERVER,"jetty"); fields1.add("Custom-Key","Other-Value"); - Response original1 = new FinalMetaData.Response(HttpVersion.HTTP_2,200,fields1); + Response original1 = new MetaData.Response(HttpVersion.HTTP_2,200,fields1); // Same again? BufferUtil.clearToFill(buffer); @@ -97,7 +96,7 @@ public class HpackTest HttpFields fields0 = new HttpFields(); fields0.add("1234567890","1234567890123456789012345678901234567890"); fields0.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); - MetaData original0= new FinalMetaData(HttpVersion.HTTP_2,fields0); + MetaData original0= new MetaData(HttpVersion.HTTP_2,fields0); BufferUtil.clearToFill(buffer); encoder.encode(buffer,original0); @@ -110,7 +109,7 @@ public class HpackTest fields1.add("1234567890","1234567890123456789012345678901234567890"); fields1.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); fields1.add("x","y"); - MetaData original1 = new FinalMetaData(HttpVersion.HTTP_2,fields1); + MetaData original1 = new MetaData(HttpVersion.HTTP_2,fields1); BufferUtil.clearToFill(buffer); encoder.encode(buffer,original1); diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java index 8de3a29fc76..7b395fbb7f8 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.http2.hpack; +import static org.junit.Assert.assertEquals; + import java.nio.ByteBuffer; import org.eclipse.jetty.util.BufferUtil; @@ -25,8 +27,6 @@ import org.eclipse.jetty.util.TypeUtil; import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.assertEquals; - public class NBitIntegerTest { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index b6cd36a0cde..900736f7f38 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -87,7 +87,7 @@ public class HttpChannelOverHTTP2 extends HttpChannel if (LOG.isDebugEnabled()) { LOG.debug("HTTP2 Request #{}:{}{} {} {}{}{}", - stream.getId(), System.lineSeparator(), request.getMethod(), request.getURI(), request.getHttpVersion(), System.lineSeparator(), fields); + stream.getId(), System.lineSeparator(), request.getMethod(), request.getURI(), request.getVersion(), System.lineSeparator(), fields); } execute(this); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index c6b2744d61f..e9e8ad69b1e 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.http2.server; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; @@ -82,7 +81,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport System.lineSeparator(), info.getHttpFields()); } - MetaData metaData = new FinalMetaData.Response(HttpVersion.HTTP_2, info.getStatus(), info.getHttpFields()); + MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2, info.getStatus(), info.getHttpFields()); HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, endStream); stream.headers(frame, callback); } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index e9700374f38..15c0b7996ff 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -34,7 +34,6 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; @@ -100,8 +99,8 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), - new HostPortHttpField(host + ":" + port), path, fields); + MetaData.Request metaData = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP, new HostPortHttpField(host + ":" + port), + path, HttpVersion.HTTP_2, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, request); @@ -149,8 +148,8 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2, HttpScheme.HTTP, HttpMethod.GET.asString(), - new HostPortHttpField(host + ":" + port), path, fields); + MetaData.Request metaData = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP, new HostPortHttpField(host + ":" + port), + path, HttpVersion.HTTP_2, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, request); @@ -212,8 +211,8 @@ public class HTTP2ServerTest String host = "localhost"; int port = connector.getLocalPort(); HttpFields fields = new HttpFields(); - MetaData.Request metaData = new FinalMetaData.Request(HttpVersion.HTTP_2,HttpScheme.HTTP, HttpMethod.GET.asString(), - new HostPortHttpField(host + ":" + port), path, fields); + MetaData.Request metaData = new MetaData.Request(HttpMethod.GET.asString(),HttpScheme.HTTP, new HostPortHttpField(host + ":" + port), + path, HttpVersion.HTTP_2, fields); HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, request); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java index ff8f14763dc..883eda6d0ac 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.server; import java.net.InetSocketAddress; +import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; @@ -46,7 +47,7 @@ import org.eclipse.jetty.server.HttpConfiguration.Customizer; */ public class ForwardedRequestCustomizer implements Customizer { - private String _hostHeader; + private HostPortHttpField _hostHeader; private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString(); private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString(); private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString(); @@ -58,7 +59,7 @@ public class ForwardedRequestCustomizer implements Customizer /* ------------------------------------------------------------ */ public String getHostHeader() { - return _hostHeader; + return _hostHeader.getValue(); } /* ------------------------------------------------------------ */ @@ -70,7 +71,7 @@ public class ForwardedRequestCustomizer implements Customizer */ public void setHostHeader(String hostHeader) { - _hostHeader = hostHeader; + _hostHeader = new HostPortHttpField(hostHeader); } /* ------------------------------------------------------------ */ @@ -224,18 +225,17 @@ public class ForwardedRequestCustomizer implements Customizer if (_hostHeader != null) { // Update host header - httpFields.put(HttpHeader.HOST.toString(),_hostHeader); - request.setServerName(null); - request.setServerPort(-1); - request.getServerName(); + httpFields.put(_hostHeader); + request.setServerName(_hostHeader.getHost()); + request.setServerPort(_hostHeader.getPort()); } else if (forwardedHost != null) { // Update host header - httpFields.put(HttpHeader.HOST.toString(),forwardedHost); - request.setServerName(null); - request.setServerPort(-1); - request.getServerName(); + HostPortHttpField auth = new HostPortHttpField(forwardedHost); + httpFields.put(auth); + request.setServerName(auth.getHost()); + request.setServerPort(auth.getPort()); } else if (forwardedServer != null) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index fd60d3ebf67..266ed8fbb54 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; -import org.eclipse.jetty.http.AbstractMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -34,9 +33,11 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; +import org.omg.stub.java.rmi._Remote_Stub; /** * A HttpChannel customized to be transported over the HTTP/1 protocol @@ -44,64 +45,22 @@ import org.eclipse.jetty.io.EndPoint; class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandler, HttpParser.ProxyHandler { private final HttpConnection _httpConnection; - private String _method; - private String _uri; - private HttpVersion _version; private final HttpFields _fields = new HttpFields(); - private HostPortHttpField _hostPort; private HttpField _connection; private boolean _expect = false; private boolean _expect100Continue = false; private boolean _expect102Processing = false; - private final MetaData.Request _metadata = new AbstractMetaData.Request() - { - @Override - public String getMethod() - { - return _method; - } - - @Override - public HttpScheme getScheme() - { - return HttpScheme.HTTP; - } - - @Override - public String getHost() - { - return _hostPort==null?null:_hostPort.getHost(); - } - - @Override - public int getPort() - { - return _hostPort==null?0:_hostPort.getPort(); - } - - @Override - public String getURI() - { - return _uri; - } - - @Override - public HttpVersion getHttpVersion() - { - return _version; - } - - @Override - public HttpFields getFields() - { - return _fields; - } - }; + + private final HttpURI _uri = new HttpURI(); + private final MetaData.Request _metadata = new MetaData.Request(); + public HttpChannelOverHttp(HttpConnection httpConnection, Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) { super(connector,config,endPoint,transport,input); _httpConnection = httpConnection; + _metadata.setFields(_fields); + _metadata.setURI(_uri); } @Override @@ -111,10 +70,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl _expect = false; _expect100Continue = false; _expect102Processing = false; - _method=null; - _uri=null; - _version=null; - _hostPort=null; + _uri.clear(); _connection=null; _fields.clear(); } @@ -134,9 +90,9 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl @Override public boolean startRequest(String method, String uri, HttpVersion version) { - _method=method; - _uri=uri; - _version=version; + _metadata.setMethod(method); + _uri.parse(uri); + _metadata.setHttpVersion(version); _expect = false; _expect100Continue = false; _expect102Processing = false; @@ -146,7 +102,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl @Override public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort) { - _method=HttpMethod.CONNECT.asString(); + _metadata.setMethod(HttpMethod.CONNECT.asString()); Request request = getRequest(); request.setAttribute("PROXY", protocol); request.setServerName(sAddr); @@ -168,12 +124,16 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl break; case HOST: - _hostPort=(HostPortHttpField)field; + if (!_uri.isAbsolute() && field instanceof HostPortHttpField) + { + HostPortHttpField hp = (HostPortHttpField)field; + _uri.setAuth(hp.getHost(),hp.getPort()); + } break; case EXPECT: { - if (_version==HttpVersion.HTTP_1_1) + if (_metadata.getVersion()==HttpVersion.HTTP_1_1) { HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) @@ -253,7 +213,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl public void earlyEOF() { // If we have no request yet, just close - if (_method==null) + if (_metadata.getMethod()==null) _httpConnection.close(); else onEarlyEOF(); @@ -279,7 +239,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl { boolean persistent; - switch (_version) + switch (_metadata.getVersion()) { case HTTP_1_0: { @@ -294,7 +254,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl persistent=false; if (!persistent) - persistent = HttpMethod.CONNECT.is(_method); + persistent = HttpMethod.CONNECT.is(_metadata.getMethod()); if (persistent) getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); @@ -320,7 +280,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl persistent=true; if (!persistent) - persistent = HttpMethod.CONNECT.is(_method); + persistent = HttpMethod.CONNECT.is(_metadata.getMethod()); if (!persistent) getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); break; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 7ca5312d280..a0b12aaced2 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -922,7 +922,7 @@ public class Request implements HttpServletRequest @Override public String getProtocol() { - return _metadata==null?null:_metadata.getHttpVersion().toString(); + return _metadata==null?null:_metadata.getVersion().toString(); } /* ------------------------------------------------------------ */ @@ -931,7 +931,7 @@ public class Request implements HttpServletRequest */ public HttpVersion getHttpVersion() { - return _metadata==null?null:_metadata.getHttpVersion(); + return _metadata==null?null:_metadata.getVersion(); } /* ------------------------------------------------------------ */ @@ -1117,7 +1117,7 @@ public class Request implements HttpServletRequest public String getRequestURI() { if (_requestURI == null && _uri != null) - _requestURI = _uri.getPathAndParam(); + _requestURI = _uri.getPath(); return _requestURI; } @@ -1537,9 +1537,11 @@ public class Request implements HttpServletRequest { _metadata=request; setMethod(request.getMethod()); - setScheme(request.getScheme().asString()); - - HttpURI uri = new HttpURI(request.getURI()); + HttpURI uri = request.getURI(); + + String scheme=uri.getScheme(); + if (scheme!=null) + setScheme(scheme); String uriHost=uri.getHost(); if (uriHost!=null) @@ -1548,29 +1550,32 @@ public class Request implements HttpServletRequest setServerName(uriHost); setServerPort(uri.getPort()); } - else - { - setServerName(request.getHost()); - setServerPort(request.getPort()); - } setUri(uri); String path = uri.getDecodedPath(); - - String info = URIUtil.canonicalPath(path); // TODO should this be done prior to decoding??? - - if (info == null) + String info; + if (path==null || path.length()==0) { - if( path==null && uri.getScheme()!=null && uri.getHost()!=null) - { - info = "/"; - setRequestURI(""); - } + if (uri.isAbsolute()) + path="/"; else throw new BadMessageException(400,"Bad URI"); + info=path; } + else if (!path.startsWith("/")) + { + if (!"*".equals(path) && !HttpMethod.CONNECT.is(getMethod())) + throw new BadMessageException(400,"Bad URI"); + info=path; + } + else + info = URIUtil.canonicalPath(path);// TODO should this be done prior to decoding??? + + if (info == null) + throw new BadMessageException(400,"Bad URI"); + setPathInfo(info); } @@ -2010,7 +2015,6 @@ public class Request implements HttpServletRequest * @param uri * The uri to set. */ - @Deprecated // is this still needed or can we use meta data? public void setUri(HttpURI uri) { _uri = uri; diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index ca1353d2104..a82dcfc5a27 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -20,13 +20,11 @@ package org.eclipse.jetty.spdy.server.http; import java.nio.ByteBuffer; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; @@ -164,7 +162,7 @@ public class HttpChannelOverSPDY extends HttpChannel // At last, add the Host header. fields.add(hostPort); - MetaData.Request request = new FinalMetaData.Request(httpVersion, HttpScheme.HTTP.asString(), httpMethod==null?methodHeader.getValue():httpMethod.asString(), uriHeader.getValue(), fields, hostPort); + MetaData.Request request = new MetaData.Request(httpMethod==null?methodHeader.getValue():httpMethod.asString(), HttpScheme.HTTP.asString(), hostPort, uriHeader.getValue(), httpVersion, fields); onRequest(request); return true; } diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java index eec770d7504..6ec67bcc832 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java @@ -18,6 +18,10 @@ package org.eclipse.jetty.spdy.server.http; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; + import java.io.IOException; import java.io.PrintWriter; import java.net.InetSocketAddress; @@ -27,6 +31,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; + import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -63,10 +68,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest { private static final Logger LOG = Log.getLogger(ReferrerPushStrategyTest.class); diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java index 0f450e2ce63..4a7ea452793 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java @@ -18,6 +18,9 @@ package org.eclipse.jetty.spdy.server.proxy; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -62,9 +65,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - @RunWith(Parameterized.class) public class ProxyHTTPToSPDYTest { diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java index 9e723036f32..2c318efdbf0 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java @@ -18,6 +18,11 @@ package org.eclipse.jetty.spdy.server.proxy; +import static junit.framework.Assert.fail; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.InetSocketAddress; @@ -33,6 +38,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -71,11 +77,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import static junit.framework.Assert.fail; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; - @Ignore @RunWith(value = Parameterized.class) public abstract class ProxySPDYToHTTPLoadTest diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java index 219ebde0706..cee18e154c9 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java @@ -18,6 +18,11 @@ package org.eclipse.jetty.spdy.server.proxy; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -27,6 +32,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -69,11 +75,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - @RunWith(value = Parameterized.class) public abstract class ProxySPDYToHTTPTest { diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java index 89f0eced800..195cd64e735 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java @@ -18,6 +18,10 @@ package org.eclipse.jetty.spdy.server.proxy; +import static junit.framework.Assert.fail; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + import java.io.ByteArrayOutputStream; import java.net.InetSocketAddress; import java.util.ArrayList; @@ -60,10 +64,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import static junit.framework.Assert.fail; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - @RunWith(value = Parameterized.class) public abstract class ProxySPDYToSPDYLoadTest { diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java index 04e9551cd55..0a0b1930b88 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java @@ -18,6 +18,9 @@ package org.eclipse.jetty.spdy.server.proxy; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + import java.io.ByteArrayOutputStream; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; @@ -62,9 +65,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - @RunWith(value = Parameterized.class) public abstract class ProxySPDYToSPDYTest { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java index adf1b770d33..f8865e0441d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java @@ -780,6 +780,16 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable } } } + + /* -------------------------------------------------------------- */ + /** Decode String with % encoding. + * This method makes the assumption that the majority of calls + * will need no decoding. + */ + public static String decodeString(String encoded) + { + return decodeString(encoded,0,encoded.length(),ENCODING); + } /* -------------------------------------------------------------- */ /** Decode String with % encoding. From 22e57ef7b727f24e41cc0040bfe47889bf3d7705 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 25 Jul 2014 15:03:51 +1000 Subject: [PATCH 153/269] refactored Request to use new HttpURI --- .../java/org/eclipse/jetty/http/HttpURI.java | 47 +++- .../org/eclipse/jetty/http/HttpURITest.java | 45 ++++ .../rewrite/handler/CompactPathRule.java | 2 +- .../rewrite/handler/RewritePatternRule.java | 6 +- .../rewrite/handler/RewriteRegexRule.java | 6 +- .../jetty/rewrite/handler/RuleContainer.java | 2 +- .../ForwardedSchemeHeaderRuleTest.java | 4 +- .../rewrite/handler/PatternRuleTest.java | 6 +- .../rewrite/handler/RewriteHandlerTest.java | 16 +- .../handler/RewritePatternRuleTest.java | 4 +- .../rewrite/handler/RewriteRegexRuleTest.java | 8 +- .../rewrite/handler/ValidUrlRuleTest.java | 12 +- .../handler/VirtualHostRuleContainerTest.java | 36 +-- .../org/eclipse/jetty/server/Dispatcher.java | 4 +- .../server/ForwardedRequestCustomizer.java | 8 +- .../jetty/server/HostHeaderCustomizer.java | 6 +- .../jetty/server/HttpChannelOverHttp.java | 5 +- .../org/eclipse/jetty/server/Request.java | 216 +++++++++--------- .../org/eclipse/jetty/server/Response.java | 10 +- .../java/org/eclipse/jetty/server/Server.java | 5 +- .../eclipse/jetty/server/ResponseTest.java | 13 +- .../spdy/server/http/HttpChannelOverSPDY.java | 18 +- .../jetty/webapp/WebAppContextTest.java | 6 +- .../test/support/TestableJettyServer.java | 6 +- .../rawhttp/HttpResponseTesterTest.java | 6 +- .../src/test/resources/BIOHttp.xml | 1 - .../src/test/resources/BIOHttps.xml | 1 - .../src/test/resources/NIOHttp.xml | 1 - .../src/test/resources/NIOHttps.xml | 1 - 29 files changed, 291 insertions(+), 210 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index f9c48a2f73f..27116557472 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -394,6 +394,12 @@ public class HttpURI state=State.PATH; break; } + case ';': + { + // multiple parameters + m=i+1; + break; + } } continue; } @@ -624,18 +630,55 @@ public class HttpURI return toString().equals(o.toString()); } + /* ------------------------------------------------------------ */ + public void setScheme(String scheme) + { + _scheme=scheme; + _uri=null; + } + /* ------------------------------------------------------------ */ /** * @param host * @param port */ - public void setAuth(String host, int port) + public void setAuthority(String host, int port) { _host=host; _port=port; _uri=null; } + /* ------------------------------------------------------------ */ + /** + * @param path + */ + public void setPath(String path) + { + _uri=null; + _path=path; + _decodedPath=null; + } + + /* ------------------------------------------------------------ */ + public void setPathQuery(String path) + { + _uri=null; + _path=null; + _decodedPath=null; + _param=null; + _fragment=null; + if (path!=null) + parse(State.PATH,path,0,path.length()); + } + + /* ------------------------------------------------------------ */ + public void setQuery(String query) + { + _query=query; + _uri=null; + } + /* ------------------------------------------------------------ */ public URI toURI() throws URISyntaxException { @@ -657,4 +700,6 @@ public class HttpURI return _host+":"+_port; return _host; } + + } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java index 1557a8425ff..a56de846328 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java @@ -246,4 +246,49 @@ public class HttpURITest assertEquals("jsessionid=12345",uri.getParam()); } + + @Test + public void testMutableURI() + { + HttpURI uri = new HttpURI("/foo/bar"); + assertEquals("/foo/bar",uri.toString()); + assertEquals("/foo/bar",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + + uri.setScheme("http"); + assertEquals("http:/foo/bar",uri.toString()); + assertEquals("/foo/bar",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + + uri.setAuthority("host",0); + assertEquals("http://host/foo/bar",uri.toString()); + assertEquals("/foo/bar",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + + uri.setAuthority("host",8888); + assertEquals("http://host:8888/foo/bar",uri.toString()); + assertEquals("/foo/bar",uri.getPath()); + assertEquals("/foo/bar",uri.getDecodedPath()); + + uri.setPathQuery("/f%30%30;p0/bar;p1;p2"); + assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2",uri.toString()); + assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath()); + assertEquals("/f00/bar",uri.getDecodedPath()); + assertEquals("p2",uri.getParam()); + assertEquals(null,uri.getQuery()); + + uri.setPathQuery("/f%30%30;p0/bar;p1;p2?name=value"); + assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?name=value",uri.toString()); + assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath()); + assertEquals("/f00/bar",uri.getDecodedPath()); + assertEquals("p2",uri.getParam()); + assertEquals("name=value",uri.getQuery()); + + uri.setQuery("other=123456"); + assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?other=123456",uri.toString()); + assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath()); + assertEquals("/f00/bar",uri.getDecodedPath()); + assertEquals("p2",uri.getParam()); + assertEquals("other=123456",uri.getQuery()); + } } diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/CompactPathRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/CompactPathRule.java index 13f2f0925b2..37306b523ec 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/CompactPathRule.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/CompactPathRule.java @@ -43,7 +43,7 @@ public class CompactPathRule extends Rule implements Rule.ApplyURI String uri = request.getRequestURI(); if (uri.startsWith("/")) uri = URIUtil.compactPath(uri); - request.setRequestURI(uri); + request.setURIPathQuery(uri); } @Override diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewritePatternRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewritePatternRule.java index eca9da67665..2aec89bd405 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewritePatternRule.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewritePatternRule.java @@ -88,7 +88,7 @@ public class RewritePatternRule extends PatternRule implements Rule.ApplyURI { if (_query == null) { - request.setRequestURI(newURI); + request.setURIPathQuery(newURI); } else { @@ -97,9 +97,7 @@ public class RewritePatternRule extends PatternRule implements Rule.ApplyURI queryString = queryString + "&" + _query; else queryString = _query; - HttpURI uri = new HttpURI(newURI + "?" + queryString); - request.setUri(uri); - request.setRequestURI(newURI); + request.setURIPathQuery(newURI); request.setQueryString(queryString); } } diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.java index f9fd8a347d0..9a664317bc9 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.java @@ -100,7 +100,7 @@ public class RewriteRegexRule extends RegexRule implements Rule.ApplyURI { if (_query==null) { - request.setRequestURI(newURI); + request.setURIPathQuery(newURI); } else { @@ -108,9 +108,7 @@ public class RewriteRegexRule extends RegexRule implements Rule.ApplyURI if (!_queryGroup && request.getQueryString()!=null) query=request.getQueryString()+"&"+query; - HttpURI uri=new HttpURI(newURI+"?"+query); - request.setUri(uri); - request.setRequestURI(newURI); + request.setURIPathQuery(newURI); request.setQueryString(query); } } diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java index f20e9142c79..20d78778d5f 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java @@ -216,7 +216,7 @@ public class RuleContainer extends Rule if (rule instanceof Rule.ApplyURI) ((Rule.ApplyURI)rule).applyURI((Request)request,((Request)request).getRequestURI(), encoded); else - ((Request)request).setRequestURI(encoded); + ((Request)request).setURIPathQuery(encoded); } if (_rewritePathInfo) diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java index f802c74f001..def9a87fd6f 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java @@ -73,11 +73,11 @@ public class ForwardedSchemeHeaderRuleTest extends AbstractRuleTestCase _rule.matchAndApply("/",_request,_response); assertEquals("https",_request.getScheme()); - _request.setScheme(null); + _request.setScheme("other"); // header value doesn't match rule's value setRequestHeader("Front-End-Https", "off"); _rule.matchAndApply("/",_request,_response); - assertEquals(null,_request.getScheme()); + assertEquals("other",_request.getScheme()); _request.setScheme(null); // header value can be any value diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java index 65dcbbdc562..cdeadce9345 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java @@ -25,6 +25,10 @@ import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.server.Request; import org.junit.After; import org.junit.Before; @@ -138,7 +142,7 @@ public class PatternRuleTest new Request(null,null) { { - setRequestURI(uri); + setMetaData(new MetaData.Request("GET",new HttpURI(uri),HttpVersion.HTTP_1_0,new HttpFields())); } }, null ); diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java index 907df35143f..c4b8153a09f 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java @@ -85,7 +85,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _handler.setOriginalPathAttribute("/before"); _handler.setRewriteRequestURI(true); _handler.setRewritePathInfo(true); - _request.setRequestURI("/xxx/bar"); + _request.setURIPathQuery("/xxx/bar"); _request.setPathInfo("/xxx/bar"); _handler.handle("/xxx/bar",_request,_request, _response); assertEquals(201,_response.getStatus()); @@ -99,7 +99,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _handler.setOriginalPathAttribute("/before"); _handler.setRewriteRequestURI(false); _handler.setRewritePathInfo(false); - _request.setRequestURI("/foo/bar"); + _request.setURIPathQuery("/foo/bar"); _request.setPathInfo("/foo/bar"); _handler.handle("/foo/bar",_request,_request, _response); @@ -112,7 +112,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _response.setStatus(200); _request.setHandled(false); _handler.setOriginalPathAttribute(null); - _request.setRequestURI("/aaa/bar"); + _request.setURIPathQuery("/aaa/bar"); _request.setPathInfo("/aaa/bar"); _handler.handle("/aaa/bar",_request,_request, _response); assertEquals(201,_response.getStatus()); @@ -126,7 +126,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _handler.setOriginalPathAttribute("before"); _handler.setRewriteRequestURI(true); _handler.setRewritePathInfo(true); - _request.setRequestURI("/aaa/bar"); + _request.setURIPathQuery("/aaa/bar"); _request.setPathInfo("/aaa/bar"); _handler.handle("/aaa/bar",_request,_request, _response); assertEquals(201,_response.getStatus()); @@ -138,7 +138,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _response.setStatus(200); _request.setHandled(false); _rule2.setTerminating(true); - _request.setRequestURI("/aaa/bar"); + _request.setURIPathQuery("/aaa/bar"); _request.setPathInfo("/aaa/bar"); _handler.handle("/aaa/bar",_request,_request, _response); assertEquals(201,_response.getStatus()); @@ -154,7 +154,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _request.setAttribute("target",null); _request.setAttribute("URI",null); _request.setAttribute("info",null); - _request.setRequestURI("/aaa/bar"); + _request.setURIPathQuery("/aaa/bar"); _request.setPathInfo("/aaa/bar"); _handler.handle("/aaa/bar",_request,_request, _response); assertEquals(200,_response.getStatus()); @@ -174,7 +174,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _handler.setOriginalPathAttribute("/before"); _handler.setRewriteRequestURI(true); _handler.setRewritePathInfo(false); - _request.setRequestURI("/ccc/x%20y"); + _request.setURIPathQuery("/ccc/x%20y"); _request.setPathInfo("/ccc/x y"); _handler.handle("/ccc/x y",_request,_request, _response); assertEquals(201,_response.getStatus()); @@ -193,7 +193,7 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _handler.setOriginalPathAttribute("/before"); _handler.setRewriteRequestURI(true); _handler.setRewritePathInfo(false); - _request.setRequestURI("/xxx/x%20y"); + _request.setURIPathQuery("/xxx/x%20y"); _request.setPathInfo("/xxx/x y"); _handler.handle("/xxx/x y",_request,_request, _response); assertEquals(201,_response.getStatus()); diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java index b3bbcc98bdc..3d2ec08d3e7 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java @@ -88,7 +88,7 @@ public class RewritePatternRuleTest extends AbstractRuleTestCase { String replacement = "/replace"; String queryString = "request=parameter"; - _request.setUri(new HttpURI("/old/context")); + _request.setURIPathQuery("/old/context"); _request.setQueryString(queryString); RewritePatternRule rewritePatternRule = new RewritePatternRule(); @@ -111,7 +111,7 @@ public class RewritePatternRuleTest extends AbstractRuleTestCase String[] split = replacement.split("\\?", 2); String path = split[0]; String queryString = split[1]; - _request.setUri(new HttpURI("/old/context")); + _request.setURIPathQuery("/old/context"); _request.setQueryString(requestQueryString); RewritePatternRule rewritePatternRule = new RewritePatternRule(); diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java index 7cf8f2ccb02..e504d36f706 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java @@ -66,15 +66,13 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase for (String[] test : _tests) { reset(); - _request.setRequestURI(null); + _request.setURIPathQuery(null); String t=test[0]+"?"+test[1]+">"+test[2]+"|"+test[3]; _rule.setRegex(test[2]); _rule.setReplacement(test[3]); - _request.setUri(new HttpURI(test[0]+(test[1]==null?"":("?"+test[1])))); - _request.getRequestURI(); - + _request.setURIPathQuery(test[0]+(test[1]==null?"":("?"+test[1]))); String result = _rule.matchAndApply(test[0], _request, _response); assertEquals(t, test[4], result); @@ -110,7 +108,7 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase _rule.setRegex(test[2]); _rule.setReplacement(test[3]); - _request.setRequestURI(test[0]); + _request.setURIPathQuery(test[0]); _request.setQueryString(test[1]); _request.getAttributes().clearAttributes(); diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java index e8d6cda940e..697945a0b9e 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java @@ -41,7 +41,7 @@ public class ValidUrlRuleTest extends AbstractRuleTestCase public void testValidUrl() throws Exception { _rule.setCode("404"); - _request.setRequestURI("/valid/uri.html"); + _request.setURIPathQuery("/valid/uri.html"); _rule.matchAndApply(_request.getRequestURI(), _request, _response); @@ -52,7 +52,7 @@ public class ValidUrlRuleTest extends AbstractRuleTestCase public void testInvalidUrl() throws Exception { _rule.setCode("404"); - _request.setRequestURI("/invalid%0c/uri.html"); + _request.setURIPathQuery("/invalid%0c/uri.html"); String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); @@ -64,7 +64,7 @@ public class ValidUrlRuleTest extends AbstractRuleTestCase { _rule.setCode("405"); _rule.setReason("foo"); - _request.setRequestURI("/%00/"); + _request.setURIPathQuery("/%00/"); String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); @@ -77,7 +77,7 @@ public class ValidUrlRuleTest extends AbstractRuleTestCase { _rule.setCode("405"); _rule.setReason("foo"); - _request.setRequestURI("/jsp/bean1.jsp%00"); + _request.setURIPathQuery("/jsp/bean1.jsp%00"); String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); @@ -91,7 +91,7 @@ public class ValidUrlRuleTest extends AbstractRuleTestCase { _rule.setCode("405"); _rule.setReason("foo"); - _request.setRequestURI("/jsp/shamrock-%00%E2%98%98.jsp"); + _request.setURIPathQuery("/jsp/shamrock-%00%E2%98%98.jsp"); String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); @@ -105,7 +105,7 @@ public class ValidUrlRuleTest extends AbstractRuleTestCase { _rule.setCode("405"); _rule.setReason("foo"); - _request.setRequestURI("/jsp/shamrock-%E2%98%98.jsp"); + _request.setURIPathQuery("/jsp/shamrock-%E2%98%98.jsp"); String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java index 2fa93e07e8d..426329d8966 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java @@ -49,7 +49,7 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase _fooContainerRule.setRules(new Rule[] { _fooRule }); start(false); - _request.setRequestURI("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); _handler.setServer(_server); _handler.start(); @@ -58,7 +58,7 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase @Test public void testArbitraryHost() throws Exception { - _request.setServerName("cheese.com"); + _request.setAuthority("cheese.com",0); _handler.setRules(new Rule[] { _rule, _fooContainerRule }); handleRequest(); assertEquals("{_rule, _fooContainerRule, Host: cheese.com}: applied _rule", "/rule/bar", _request.getRequestURI()); @@ -67,7 +67,7 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase @Test public void testVirtualHost() throws Exception { - _request.setServerName("foo.com"); + _request.setAuthority("foo.com",0); _handler.setRules(new Rule[] { _fooContainerRule }); handleRequest(); assertEquals("{_fooContainerRule, Host: foo.com}: applied _fooRule", "/cheese/fooRule", _request.getRequestURI()); @@ -76,8 +76,8 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase @Test public void testCascadingRules() throws Exception { - _request.setServerName("foo.com"); - _request.setRequestURI("/cheese/bar"); + _request.setAuthority("foo.com",0); + _request.setURIPathQuery("/cheese/bar"); _rule.setTerminating(false); _fooRule.setTerminating(false); @@ -87,17 +87,17 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase handleRequest(); assertEquals("{_rule, _fooContainerRule}: applied _rule, didn't match _fooRule", "/rule/bar", _request.getRequestURI()); - _request.setRequestURI("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); _handler.setRules(new Rule[] { _fooContainerRule, _rule }); handleRequest(); assertEquals("{_fooContainerRule, _rule}: applied _fooRule, _rule","/rule/fooRule", _request.getRequestURI()); - _request.setRequestURI("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); _fooRule.setTerminating(true); handleRequest(); assertEquals("{_fooContainerRule, _rule}: (_fooRule is terminating); applied _fooRule, _rule", "/rule/fooRule", _request.getRequestURI()); - _request.setRequestURI("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); _fooRule.setTerminating(false); _fooContainerRule.setTerminating(true); handleRequest(); @@ -107,7 +107,7 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase @Test public void testCaseInsensitiveHostname() throws Exception { - _request.setServerName("Foo.com"); + _request.setAuthority("Foo.com",0); _fooContainerRule.setVirtualHosts(new String[] {"foo.com"} ); _handler.setRules(new Rule[]{ _fooContainerRule }); @@ -118,21 +118,21 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase @Test public void testEmptyVirtualHost() throws Exception { - _request.setServerName("cheese.com"); + _request.setAuthority("cheese.com",0); _handler.setRules(new Rule[] { _fooContainerRule }); _fooContainerRule.setVirtualHosts(null); handleRequest(); assertEquals("{_fooContainerRule: virtual hosts array is null, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); - _request.setRequestURI("/cheese/bar"); - _request.setRequestURI("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); _fooContainerRule.setVirtualHosts(new String[] {}); handleRequest(); assertEquals("{_fooContainerRule: virtual hosts array is empty, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); - _request.setRequestURI("/cheese/bar"); - _request.setRequestURI("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); _fooContainerRule.setVirtualHosts(new String[] {null}); handleRequest(); assertEquals("{_fooContainerRule: virtual host is null, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); @@ -142,14 +142,14 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase @Test public void testMultipleVirtualHosts() throws Exception { - _request.setServerName("foo.com"); + _request.setAuthority("foo.com",0); _handler.setRules(new Rule[] {_fooContainerRule }); _fooContainerRule.setVirtualHosts(new String[]{ "cheese.com" }); handleRequest(); assertEquals("{_fooContainerRule: vhosts[cheese.com], Host: foo.com}: no effect", "/cheese/bar", _request.getRequestURI()); - _request.setRequestURI("/cheese/bar"); + _request.setURIPathQuery("/cheese/bar"); _fooContainerRule.addVirtualHost( "foo.com" ); handleRequest(); assertEquals("{_fooContainerRule: vhosts[cheese.com, foo.com], Host: foo.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); @@ -182,8 +182,8 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase for(String host: requestHosts) { - _request.setServerName(host); - _request.setRequestURI("/cheese/bar"); + _request.setAuthority(host,0); + _request.setURIPathQuery("/cheese/bar"); handleRequest(); if(succeed) assertEquals("{_fooContainerRule, Host: "+host+"}: should apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java index 25672897948..ba16beeb379 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java @@ -180,7 +180,7 @@ public class Dispatcher implements RequestDispatcher attr._servletPath=old_servlet_path; } - baseRequest.setRequestURI(_uri); + baseRequest.setURIPathQuery(_uri); baseRequest.setContextPath(_contextHandler.getContextPath()); baseRequest.setServletPath(null); baseRequest.setPathInfo(_uri); @@ -197,7 +197,7 @@ public class Dispatcher implements RequestDispatcher finally { baseRequest.setHandled(old_handled); - baseRequest.setRequestURI(old_uri); + baseRequest.setURIPathQuery(old_uri); baseRequest.setContextPath(old_context_path); baseRequest.setServletPath(old_servlet_path); baseRequest.setPathInfo(old_path_info); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java index 883eda6d0ac..f2943cfa5e6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java @@ -226,21 +226,19 @@ public class ForwardedRequestCustomizer implements Customizer { // Update host header httpFields.put(_hostHeader); - request.setServerName(_hostHeader.getHost()); - request.setServerPort(_hostHeader.getPort()); + request.setAuthority(_hostHeader.getHost(),_hostHeader.getPort()); } else if (forwardedHost != null) { // Update host header HostPortHttpField auth = new HostPortHttpField(forwardedHost); httpFields.put(auth); - request.setServerName(auth.getHost()); - request.setServerPort(auth.getPort()); + request.setAuthority(auth.getHost(),auth.getPort()); } else if (forwardedServer != null) { // Use provided server name - request.setServerName(forwardedServer); + request.setAuthority(forwardedServer,request.getServerPort()); } if (forwardedFor != null) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java index 7911351ef00..6303ddec3f8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java @@ -62,10 +62,6 @@ public class HostHeaderCustomizer implements HttpConfiguration.Customizer public void customize(Connector connector, HttpConfiguration channelConfig, Request request) { if (request.getHeader("Host") == null) - { - request.setServerName(serverName); - if (serverPort > 0) - request.setServerPort(serverPort); - } + request.setAuthority(serverName,serverPort); // TODO set the field as well? } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 266ed8fbb54..7df3856d625 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -105,8 +105,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl _metadata.setMethod(HttpMethod.CONNECT.asString()); Request request = getRequest(); request.setAttribute("PROXY", protocol); - request.setServerName(sAddr); - request.setServerPort(dPort); + request.setAuthority(sAddr,dPort); request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort)); } @@ -127,7 +126,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl if (!_uri.isAbsolute() && field instanceof HostPortHttpField) { HostPortHttpField hp = (HostPortHttpField)field; - _uri.setAuth(hp.getHost(),hp.getPort()); + _uri.setAuthority(hp.getHost(),hp.getPort()); } break; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index a0b12aaced2..5e5efea1890 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -67,6 +67,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; @@ -133,6 +134,11 @@ public class Request implements HttpServletRequest private final HttpInput _input; private MetaData.Request _metadata; + + private String _contextPath; + private String _servletPath; + private String _pathInfo; + private boolean _secure; private boolean _asyncSupported = true; private boolean _newContext; @@ -144,32 +150,22 @@ public class Request implements HttpServletRequest private Authentication _authentication; private String _characterEncoding; private ContextHandler.Context _context; - private String _contextPath; private CookieCutter _cookies; private DispatcherType _dispatcherType; private int _inputState = __NONE; - private String _httpMethod; private MultiMap<String> _queryParameters; private MultiMap<String> _contentParameters; private MultiMap<String> _parameters; - private String _pathInfo; - private int _serverPort; private String _queryEncoding; - private String _queryString; private BufferedReader _reader; private String _readerEncoding; private InetSocketAddress _remote; private String _requestedSessionId; - private String _requestURI; private Map<Object, HttpSession> _savedNewSessions; - private String _scheme = URIUtil.HTTP; private UserIdentity.Scope _scope; - private String _serverName; - private String _servletPath; private HttpSession _session; private SessionManager _sessionManager; private long _timeStamp; - private HttpURI _uri; private MultiPartInputStreamParser _multiPartInputStream; //if the request is a multi-part mime private AsyncContextState _async; @@ -227,17 +223,17 @@ public class Request implements HttpServletRequest private MultiMap<String> extractQueryParameters() { MultiMap<String> result = new MultiMap<>(); - if (_uri != null && _uri.hasQuery()) + if (_metadata.getURI() != null && _metadata.getURI().hasQuery()) { if (_queryEncoding == null) { - _uri.decodeQueryTo(result); + _metadata.getURI().decodeQueryTo(result); } else { try { - _uri.decodeQueryTo(result, _queryEncoding); + _metadata.getURI().decodeQueryTo(result, _queryEncoding); } catch (UnsupportedEncodingException e) { @@ -763,6 +759,21 @@ public class Request implements HttpServletRequest @Override public String getLocalAddr() { + if (_channel==null) + { + try + { + String name =InetAddress.getLocalHost().getHostAddress(); + if (StringUtil.ALL_INTERFACES.equals(name)) + return null; + return name; + } + catch (java.net.UnknownHostException e) + { + LOG.ignore(e); + } + } + InetSocketAddress local=_channel.getLocalAddress(); if (local==null) return ""; @@ -779,6 +790,20 @@ public class Request implements HttpServletRequest @Override public String getLocalName() { + if (_channel==null) + { + try + { + String name =InetAddress.getLocalHost().getHostName(); + if (StringUtil.ALL_INTERFACES.equals(name)) + return null; + return name; + } + catch (java.net.UnknownHostException e) + { + LOG.ignore(e); + } + } InetSocketAddress local=_channel.getLocalAddress(); return local.getHostString(); } @@ -790,6 +815,8 @@ public class Request implements HttpServletRequest @Override public int getLocalPort() { + if (_channel==null) + return 0; InetSocketAddress local=_channel.getLocalAddress(); return local.getPort(); } @@ -801,7 +828,7 @@ public class Request implements HttpServletRequest @Override public String getMethod() { - return _httpMethod; + return _metadata.getMethod(); } /* ------------------------------------------------------------ */ @@ -947,9 +974,7 @@ public class Request implements HttpServletRequest @Override public String getQueryString() { - if (_queryString == null && _uri != null) - _queryString = _uri.getQuery(); - return _queryString; + return _metadata.getURI().getQuery(); } /* ------------------------------------------------------------ */ @@ -1116,9 +1141,7 @@ public class Request implements HttpServletRequest @Override public String getRequestURI() { - if (_requestURI == null && _uri != null) - _requestURI = _uri.getPath(); - return _requestURI; + return _metadata.getURI().getPath(); } /* ------------------------------------------------------------ */ @@ -1165,7 +1188,8 @@ public class Request implements HttpServletRequest @Override public String getScheme() { - return _scheme; + String scheme=_metadata.getURI().getScheme(); + return scheme==null?HttpScheme.HTTP.asString():scheme; } /* ------------------------------------------------------------ */ @@ -1175,52 +1199,45 @@ public class Request implements HttpServletRequest @Override public String getServerName() { + String name = _metadata.getURI().getHost(); + // Return already determined host - if (_serverName != null) - return _serverName; + if (name != null) + return name; - if (_uri == null) - throw new IllegalStateException("No uri"); - - // Return host from absolute URI - _serverName = _uri.getHost(); - if (_serverName != null) - { - _serverPort = _uri.getPort(); - return _serverName; - } + return findServerName(); + } + /* ------------------------------------------------------------ */ + private String findServerName() + { // Return host from header field HttpField host = _metadata.getFields().getField(HttpHeader.HOST); if (host!=null) { + // TODO is this needed now? HostPortHttpField authority = (host instanceof HostPortHttpField) ?((HostPortHttpField)host) :new HostPortHttpField(host.getValue()); - _serverName=authority.getHost(); - _serverPort=authority.getPort(); - return _serverName; + _metadata.getURI().setAuthority(authority.getHost(),authority.getPort()); + return authority.getHost(); } // Return host from connection - if (_channel != null) - { - _serverName = getLocalName(); - _serverPort = getLocalPort(); - if (_serverName != null && !StringUtil.ALL_INTERFACES.equals(_serverName)) - return _serverName; - } + String name=getLocalName(); + if (name != null) + return name; // Return the local host try { - _serverName = InetAddress.getLocalHost().getHostAddress(); + return InetAddress.getLocalHost().getHostAddress(); } catch (java.net.UnknownHostException e) { LOG.ignore(e); } - return _serverName; + return null; } /* ------------------------------------------------------------ */ @@ -1230,13 +1247,11 @@ public class Request implements HttpServletRequest @Override public int getServerPort() { - // If we have no port and have not decoded a server name - if (_serverPort <= 0 && _serverName == null) - // decode a server name, which will set the port if it can - getServerName(); - + HttpURI uri = _metadata.getURI(); + int port = (uri.getHost()==null)?findServerPort():uri.getPort(); + // If no port specified, return the default port for the scheme - if (_serverPort <= 0) + if (port <= 0) { if (getScheme().equalsIgnoreCase(URIUtil.HTTPS)) return 443; @@ -1244,9 +1259,31 @@ public class Request implements HttpServletRequest } // return a specific port - return _serverPort; + return port; } + /* ------------------------------------------------------------ */ + private int findServerPort() + { + // Return host from header field + HttpField host = _metadata.getFields().getField(HttpHeader.HOST); + if (host!=null) + { + // TODO is this needed now? + HostPortHttpField authority = (host instanceof HostPortHttpField) + ?((HostPortHttpField)host) + :new HostPortHttpField(host.getValue()); + _metadata.getURI().setAuthority(authority.getHost(),authority.getPort()); + return authority.getPort(); + } + + // Return host from connection + if (_channel != null) + return getLocalPort(); + + return -1; + } + /* ------------------------------------------------------------ */ @Override public ServletContext getServletContext() @@ -1373,7 +1410,7 @@ public class Request implements HttpServletRequest */ public HttpURI getUri() { - return _uri; + return _metadata.getURI(); } /* ------------------------------------------------------------ */ @@ -1539,33 +1576,22 @@ public class Request implements HttpServletRequest setMethod(request.getMethod()); HttpURI uri = request.getURI(); - String scheme=uri.getScheme(); - if (scheme!=null) - setScheme(scheme); - - String uriHost=uri.getHost(); - if (uriHost!=null) - { - // Give precidence to authority in absolute URI - setServerName(uriHost); - setServerPort(uri.getPort()); - } - - setUri(uri); - - String path = uri.getDecodedPath(); String info; if (path==null || path.length()==0) { if (uri.isAbsolute()) + { path="/"; + uri.setPath(path); + } else throw new BadMessageException(400,"Bad URI"); info=path; } else if (!path.startsWith("/")) { + System.err.println(request); if (!"*".equals(path) && !HttpMethod.CONNECT.is(getMethod())) throw new BadMessageException(400,"Bad URI"); info=path; @@ -1619,23 +1645,16 @@ public class Request implements HttpServletRequest _cookiesExtracted = false; _context = null; _newContext=false; - _serverName = null; - _httpMethod = null; _pathInfo = null; - _serverPort = 0; _queryEncoding = null; - _queryString = null; _requestedSessionId = null; _requestedSessionIdFromCookie = false; _secure=false; _session = null; _sessionManager = null; - _requestURI = null; _scope = null; - _scheme = URIUtil.HTTP; _servletPath = null; _timeStamp = 0; - _uri = null; _queryParameters = null; _contentParameters = null; _parameters = null; @@ -1859,13 +1878,13 @@ public class Request implements HttpServletRequest */ public void setMethod(String method) { - _httpMethod = method; + _metadata.setMethod(method); } /* ------------------------------------------------------------ */ public boolean isHead() { - return HttpMethod.HEAD.asString().equals(_httpMethod); + return _metadata!=null && HttpMethod.HEAD.is(_metadata.getMethod()); } /* ------------------------------------------------------------ */ @@ -1890,7 +1909,6 @@ public class Request implements HttpServletRequest public void setQueryEncoding(String queryEncoding) { _queryEncoding = queryEncoding; - _queryString = null; } /* ------------------------------------------------------------ */ @@ -1900,7 +1918,7 @@ public class Request implements HttpServletRequest */ public void setQueryString(String queryString) { - _queryString = queryString; + _metadata.getURI().setQuery(queryString); _queryEncoding = null; //assume utf-8 } @@ -1935,13 +1953,9 @@ public class Request implements HttpServletRequest } /* ------------------------------------------------------------ */ - /** - * @param requestURI - * The requestURI to set. - */ - public void setRequestURI(String requestURI) + public void setURIPathQuery(String requestURI) { - _requestURI = requestURI; + _metadata.getURI().setPathQuery(requestURI); } /* ------------------------------------------------------------ */ @@ -1951,7 +1965,7 @@ public class Request implements HttpServletRequest */ public void setScheme(String scheme) { - _scheme = scheme; + _metadata.getURI().setScheme(scheme); } /* ------------------------------------------------------------ */ @@ -1959,19 +1973,9 @@ public class Request implements HttpServletRequest * @param host * The host to set. */ - public void setServerName(String host) + public void setAuthority(String host,int port) { - _serverName = host; - } - - /* ------------------------------------------------------------ */ - /** - * @param port - * The port to set. - */ - public void setServerPort(int port) - { - _serverPort = port; + _metadata.getURI().setAuthority(host,port);; } /* ------------------------------------------------------------ */ @@ -2010,16 +2014,6 @@ public class Request implements HttpServletRequest _timeStamp = ts; } - /* ------------------------------------------------------------ */ - /** - * @param uri - * The uri to set. - */ - public void setUri(HttpURI uri) - { - _uri = uri; - } - /* ------------------------------------------------------------ */ public void setUserIdentityScope(UserIdentity.Scope scope) { @@ -2060,7 +2054,7 @@ public class Request implements HttpServletRequest @Override public String toString() { - return (_handled?"[":"(") + getMethod() + " " + _uri + (_handled?"]@":")@") + hashCode() + " " + super.toString(); + return (_handled?"[":"(") + getMethod() + " " + _metadata.getURI() + (_handled?"]@":")@") + hashCode() + " " + super.toString(); } /* ------------------------------------------------------------ */ @@ -2174,10 +2168,10 @@ public class Request implements HttpServletRequest UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING); MultiMap<String> oldQueryParams = _queryParameters; - if (oldQueryParams == null && _queryString != null) + if (oldQueryParams == null && getQueryString() != null) { oldQueryParams = new MultiMap<>(); - UrlEncoded.decodeTo(_queryString, oldQueryParams, getQueryEncoding()); + UrlEncoded.decodeTo(getQueryString(), oldQueryParams, getQueryEncoding()); } MultiMap<String> mergedQueryParams = newQueryParams; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index a8e481dfc23..366805a6f27 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -440,9 +440,13 @@ public class Response implements HttpServletResponse int port = uri.getPort(); if (port < 0) port = HttpScheme.HTTPS.asString().equalsIgnoreCase(uri.getScheme()) ? 443 : 80; - if (!request.getServerName().equalsIgnoreCase(uri.getHost()) || - request.getServerPort() != port || - !path.startsWith(request.getContextPath())) //TODO the root context path is "", with which every non null string starts + + // Is it the same server? + if (!request.getServerName().equalsIgnoreCase(uri.getHost())) + return url; + if (request.getServerPort() != port) + return url; + if (!path.startsWith(request.getContextPath())) //TODO the root context path is "", with which every non null string starts return url; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index 2582188fd09..bf77f1f314e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -519,9 +519,8 @@ public class Server extends HandlerWrapper implements Attributes { // this is a dispatch with a path ServletContext context=event.getServletContext(); - HttpURI uri = new HttpURI(URIUtil.addPaths(context==null?null:context.getContextPath(), path)); - baseRequest.setUri(uri); - baseRequest.setRequestURI(null); + baseRequest.setURIPathQuery(URIUtil.addPaths(context==null?null:context.getContextPath(), path)); + HttpURI uri = baseRequest.getUri(); baseRequest.setPathInfo(uri.getDecodedPath()); if (uri.getQuery()!=null) baseRequest.mergeQueryParameters(uri.getQuery(), true); //we have to assume dispatch path and query are UTF8 diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 82c5321dc4e..15164a50c25 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -47,6 +47,8 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator.ResponseInfo; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.AbstractEndPoint; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -415,8 +417,7 @@ public class ResponseTest { Response response = newResponse(); Request request = response.getHttpChannel().getRequest(); - request.setServerName("myhost"); - request.setServerPort(8888); + request.setAuthority("myhost",8888); request.setContextPath("/path"); assertEquals("http://myhost:8888/path/info;param?query=0&more=1#target", response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target")); @@ -491,9 +492,8 @@ public class ResponseTest Response response = newResponse(); Request request = response.getHttpChannel().getRequest(); - request.setServerName(host); - request.setServerPort(port); - request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target")); + request.setAuthority(host,port); + request.setURIPathQuery("/path/info;param;jsessionid=12345?query=0&more=1#target"); request.setContextPath("/path"); request.setRequestedSessionId("12345"); request.setRequestedSessionIdFromCookie(i>2); @@ -657,7 +657,7 @@ public class ResponseTest @Test public void testFlushAfterFullContent() throws Exception { - Response response = _channel.getResponse(); + Response response = newResponse(); byte[] data = new byte[]{(byte)0xCA, (byte)0xFE}; ServletOutputStream output = response.getOutputStream(); response.setContentLength(data.length); @@ -790,6 +790,7 @@ public class ResponseTest private Response newResponse() { _channel.reset(); + _channel.getRequest().setMetaData(new MetaData.Request("GET",new HttpURI("/path/info"),HttpVersion.HTTP_1_0,new HttpFields())); return new Response(_channel, _channel.getResponse().getHttpOutput()); } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java index a82dcfc5a27..12c8821514b 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; @@ -107,9 +107,6 @@ public class HttpChannelOverSPDY extends HttpChannel if (LOG.isDebugEnabled()) LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion); - Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version)); - if (schemeHeader != null) - getRequest().setScheme(schemeHeader.getValue()); HostPortHttpField hostPort = null; HttpFields fields = new HttpFields(); @@ -160,9 +157,18 @@ public class HttpChannelOverSPDY extends HttpChannel } // At last, add the Host header. - fields.add(hostPort); + if (hostPort!=null) + fields.add(hostPort); - MetaData.Request request = new MetaData.Request(httpMethod==null?methodHeader.getValue():httpMethod.asString(), HttpScheme.HTTP.asString(), hostPort, uriHeader.getValue(), httpVersion, fields); + Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version)); + + HttpURI uri = new HttpURI(uriHeader.getValue()); + if (uri.getScheme()==null && schemeHeader!=null) + uri.setScheme(schemeHeader.getValue()); + if (uri.getHost()==null && hostPort!=null) + uri.setAuthority(hostPort.getHost(),hostPort.getPort()); + + MetaData.Request request = new MetaData.Request(httpMethod==null?methodHeader.getValue():httpMethod.asString(), uri, httpVersion, fields); onRequest(request); return true; } diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java index ffb60b5ad3b..599a0813b17 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.webapp; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -32,8 +33,6 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; -import junit.framework.Assert; - import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; @@ -41,6 +40,7 @@ import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceCollection; +import org.junit.Assert; import org.junit.Test; public class WebAppContextTest @@ -51,7 +51,7 @@ public class WebAppContextTest Server server = new Server(); //test if no classnames set, its the defaults WebAppContext wac = new WebAppContext(); - Assert.assertEquals(0,wac.getConfigurations().length); + assertEquals(0,wac.getConfigurations().length); String[] classNames = wac.getConfigurationClasses(); assertNotNull(classNames); diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java index 4cff458db24..face854703d 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java @@ -120,7 +120,7 @@ public class TestableJettyServer for (int i = 0; i < this._xmlConfigurations.size(); i++) { URL configURL = this._xmlConfigurations.get(i); - System.err.println("configuring: "+configURL); + // System.err.println("configuring: "+configURL); XmlConfiguration configuration = new XmlConfiguration(configURL); if (last != null) { @@ -177,8 +177,8 @@ public class TestableJettyServer _server.start(); // Find the active server port. - this._serverPort = ((NetworkConnector)_server.getConnectors()[0]).getPort(); - System.err.println("Server Port="+_serverPort); + this._serverPort = ((NetworkConnector)_server.getConnectors()[0]).getLocalPort(); + // System.err.println("Server Port="+_serverPort); Assert.assertTrue("Server Port is between 1 and 65535. Actually <" + _serverPort + ">",(1 <= this._serverPort) && (this._serverPort <= 65535)); } diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java index 5c6178e344f..fe2dfcc6227 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java @@ -104,21 +104,21 @@ public class HttpResponseTesterTest Assert.assertEquals("Responses.size",3,responses.size()); HttpTester.Response resp1 = responses.get(0); - System.err.println(resp1.toString()); + // System.err.println(resp1.toString()); Assert.assertEquals(HttpStatus.OK_200, resp1.getStatus()); Assert.assertEquals("text/plain", resp1.get("Content-Type")); Assert.assertTrue(resp1.getContent().contains("ABCDEFGHIJKLMNOPQRSTTUVWXYZ\n")); assertThat(resp1.get("Connection"),is(not("close"))); HttpTester.Response resp2 = responses.get(1); - System.err.println(resp2.toString()); + // System.err.println(resp2.toString()); Assert.assertEquals(HttpStatus.OK_200, resp2.getStatus()); Assert.assertEquals("text/plain", resp2.get("Content-Type")); Assert.assertTrue(resp2.getContent().contains("Host=Default\nResource=R1\n")); assertThat(resp2.get("Connection"),is(not("close"))); HttpTester.Response resp3 = responses.get(2); - System.err.println(resp3.toString()); + // System.err.println(resp3.toString()); Assert.assertEquals(HttpStatus.OK_200, resp3.getStatus()); Assert.assertEquals("text/plain", resp3.get("Content-Type")); Assert.assertTrue(resp3.getContent().contains("Host=Default\nResource=R2\n")); diff --git a/tests/test-integration/src/test/resources/BIOHttp.xml b/tests/test-integration/src/test/resources/BIOHttp.xml index 751a3c2cd0a..1afdbe58de5 100644 --- a/tests/test-integration/src/test/resources/BIOHttp.xml +++ b/tests/test-integration/src/test/resources/BIOHttp.xml @@ -11,7 +11,6 @@ <Arg> <New class="org.eclipse.jetty.server.bio.SocketConnector"> <Set name="host"><SystemProperty name="jetty.host" /></Set> - <Set name="port"><SystemProperty name="jetty.port" default="0"/></Set> <Set name="idleTimeout">300000</Set> <Set name="Acceptors">2</Set> <Set name="statsOn">false</Set> diff --git a/tests/test-integration/src/test/resources/BIOHttps.xml b/tests/test-integration/src/test/resources/BIOHttps.xml index d845957d142..7a8f2f84b2c 100644 --- a/tests/test-integration/src/test/resources/BIOHttps.xml +++ b/tests/test-integration/src/test/resources/BIOHttps.xml @@ -11,7 +11,6 @@ <Arg> <New class="org.eclipse.jetty.server.ssl.SslSocketConnector"> <Set name="host"><SystemProperty name="jetty.host" /></Set> - <Set name="port"><SystemProperty name="jetty.port" default="0"/></Set> <Set name="idleTimeout">300000</Set> <Set name="Acceptors">2</Set> <Set name="statsOn">false</Set> diff --git a/tests/test-integration/src/test/resources/NIOHttp.xml b/tests/test-integration/src/test/resources/NIOHttp.xml index 793da7a94d1..648c945664d 100644 --- a/tests/test-integration/src/test/resources/NIOHttp.xml +++ b/tests/test-integration/src/test/resources/NIOHttp.xml @@ -21,7 +21,6 @@ </Array> </Arg> <Set name="host"><Property name="jetty.host" /></Set> - <Set name="port"><Property name="jetty.port" default="8080" /></Set> <Set name="idleTimeout"><Property name="http.timeout" default="30000"/></Set> </New> </Arg> diff --git a/tests/test-integration/src/test/resources/NIOHttps.xml b/tests/test-integration/src/test/resources/NIOHttps.xml index ff42c725fa6..d80f1da78ef 100644 --- a/tests/test-integration/src/test/resources/NIOHttps.xml +++ b/tests/test-integration/src/test/resources/NIOHttps.xml @@ -26,7 +26,6 @@ </Array> </Arg> <Set name="host"><Property name="jetty.host" /></Set> - <Set name="port"><Property name="jetty.https.port" default="8443" /></Set> <Set name="idleTimeout">30000</Set> </New> </Arg> From eaf374fa582e07f6d49184b09d72dfe84d7ace1e Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 25 Jul 2014 17:28:35 +1000 Subject: [PATCH 154/269] refactored Dispatcher for new HttpURI --- .../client/HttpClientCustomProxyTest.java | 2 +- .../jetty/client/HttpClientProxyTest.java | 2 +- .../java/org/eclipse/jetty/http/HttpURI.java | 12 ++ .../eclipse/jetty/proxy/ConnectHandler.java | 2 +- .../jetty/server/AbstractNCSARequestLog.java | 2 +- .../org/eclipse/jetty/server/Dispatcher.java | 58 ++++---- .../org/eclipse/jetty/server/HttpChannel.java | 4 +- .../jetty/server/HttpChannelOverHttp.java | 11 +- .../org/eclipse/jetty/server/Request.java | 129 ++++++++++++------ .../java/org/eclipse/jetty/server/Server.java | 5 +- .../jetty/server/handler/ContextHandler.java | 25 ++-- .../jetty/server/handler/DebugHandler.java | 2 +- .../eclipse/jetty/server/AsyncStressTest.java | 4 +- .../jetty/servlet/DispatcherForwardTest.java | 112 ++++++++------- .../http/HttpClientCustomProxyTest.java | 2 +- 15 files changed, 216 insertions(+), 156 deletions(-) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java index 308b20bf2c9..eb05fc85398 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java @@ -93,7 +93,7 @@ public class HttpClientCustomProxyTest public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); - if (!URI.create(baseRequest.getUri().toString()).isAbsolute()) + if (!URI.create(baseRequest.getHttpURI().toString()).isAbsolute()) response.setStatus(HttpServletResponse.SC_USE_PROXY); else if (serverHost.equals(request.getServerName())) response.setStatus(status); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java index 41875bfb163..89c34f30f2d 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java @@ -58,7 +58,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); - if (!URI.create(baseRequest.getUri().toString()).isAbsolute()) + if (!URI.create(baseRequest.getHttpURI().toString()).isAbsolute()) response.setStatus(HttpServletResponse.SC_USE_PROXY); else if (serverHost.equals(request.getServerName())) response.setStatus(status); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index 27116557472..26ad8e7b592 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -80,6 +80,18 @@ public class HttpURI { } + /* ------------------------------------------------------------ */ + public HttpURI(String scheme, String host, int port, String path, String param, String query, String fragment) + { + _scheme = scheme; + _host = host; + _port = port; + _path = path; + _param = param; + _query = query; + _fragment = fragment; + } + /* ------------------------------------------------------------ */ public HttpURI(String uri) { diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java index b43ce7338c3..41a4e912a48 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java @@ -195,7 +195,7 @@ public class ConnectHandler extends HandlerWrapper catch (Exception x) { // TODO - LOG.warn("ConnectHandler " + baseRequest.getUri() + " " + x); + LOG.warn("ConnectHandler " + baseRequest.getHttpURI() + " " + x); LOG.debug(x); } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java index 2a16bdd5501..f7a6bc7a3b8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java @@ -131,7 +131,7 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement buf.append("] \""); buf.append(request.getMethod()); buf.append(' '); - buf.append(request.getUri().toString()); + buf.append(request.getHttpURI().toString()); buf.append(' '); buf.append(request.getProtocol()); buf.append("\" "); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java index ba16beeb379..b296ff62aa7 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; + import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; @@ -30,6 +31,7 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.MultiMap; @@ -43,27 +45,24 @@ public class Dispatcher implements RequestDispatcher public final static String __FORWARD_PREFIX="javax.servlet.forward."; private final ContextHandler _contextHandler; - private final String _uri; - private final String _path; - private final String _query; + private final HttpURI _uri; + private final String _pathInfo; private final String _named; - public Dispatcher(ContextHandler contextHandler, String uri, String pathInContext, String query) + public Dispatcher(ContextHandler contextHandler, HttpURI uri, String pathInfo) { _contextHandler=contextHandler; _uri=uri; - _path=pathInContext; - _query=query; + _pathInfo=pathInfo; _named=null; } public Dispatcher(ContextHandler contextHandler, String name) throws IllegalStateException { _contextHandler=contextHandler; - _named=name; _uri=null; - _path=null; - _query=null; + _pathInfo=null; + _named=name; } @Override @@ -102,17 +101,17 @@ public class Dispatcher implements RequestDispatcher { IncludeAttributes attr = new IncludeAttributes(old_attr); - attr._requestURI=_uri; + attr._requestURI=_uri.getPath(); attr._contextPath=_contextHandler.getContextPath(); attr._servletPath=null; // set by ServletHandler - attr._pathInfo=_path; - attr._query=_query; + attr._pathInfo=_pathInfo; + attr._query=_uri.getQuery(); - if (_query!=null) - baseRequest.mergeQueryParameters(_query, false); + if (attr._query!=null) + baseRequest.mergeQueryParameters(baseRequest.getQueryString(),attr._query, false); baseRequest.setAttributes(attr); - _contextHandler.handle(_path, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); + _contextHandler.handle(_pathInfo, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); } } finally @@ -137,11 +136,12 @@ public class Dispatcher implements RequestDispatcher response = new ServletResponseHttpWrapper(response); final boolean old_handled=baseRequest.isHandled(); - final String old_uri=baseRequest.getRequestURI(); + + final HttpURI old_uri=baseRequest.getHttpURI(); final String old_context_path=baseRequest.getContextPath(); final String old_servlet_path=baseRequest.getServletPath(); final String old_path_info=baseRequest.getPathInfo(); - final String old_query=baseRequest.getQueryString(); + final MultiMap<String> old_query_params=baseRequest.getQueryParameters(); final Attributes old_attr=baseRequest.getAttributes(); final DispatcherType old_type=baseRequest.getDispatcherType(); @@ -174,21 +174,26 @@ public class Dispatcher implements RequestDispatcher else { attr._pathInfo=old_path_info; - attr._query=old_query; - attr._requestURI=old_uri; + attr._query=old_uri.getQuery(); + attr._requestURI=old_uri.getPath(); attr._contextPath=old_context_path; attr._servletPath=old_servlet_path; } - - baseRequest.setURIPathQuery(_uri); + + HttpURI uri = new HttpURI(old_uri.getScheme(),old_uri.getHost(),old_uri.getPort(), + _uri.getPath(),_uri.getParam(),_uri.getQuery(),_uri.getFragment()); + + baseRequest.setHttpURI(uri); + baseRequest.setContextPath(_contextHandler.getContextPath()); baseRequest.setServletPath(null); - baseRequest.setPathInfo(_uri); - if (_query!=null) - baseRequest.mergeQueryParameters(_query, true); + baseRequest.setPathInfo(_pathInfo); + if (_uri.getQuery()!=null || old_uri.getQuery()!=null) + baseRequest.mergeQueryParameters(old_uri.getQuery(),_uri.getQuery(), true); + baseRequest.setAttributes(attr); - _contextHandler.handle(_path, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); + _contextHandler.handle(_pathInfo, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); if (!baseRequest.getHttpChannelState().isAsync()) commitResponse(response,baseRequest); @@ -197,11 +202,10 @@ public class Dispatcher implements RequestDispatcher finally { baseRequest.setHandled(old_handled); - baseRequest.setURIPathQuery(old_uri); + baseRequest.setHttpURI(old_uri); baseRequest.setContextPath(old_context_path); baseRequest.setServletPath(old_servlet_path); baseRequest.setPathInfo(old_path_info); - baseRequest.setQueryString(old_query); baseRequest.setQueryParameters(old_query_params); baseRequest.resetParameters(); baseRequest.setAttributes(old_attr); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index b9daeed35a0..a07d1032f3f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -211,7 +211,7 @@ public class HttpChannel implements Runnable if (LOG.isDebugEnabled()) { threadName = Thread.currentThread().getName(); - Thread.currentThread().setName(threadName + " - " + _request.getUri()); + Thread.currentThread().setName(threadName + " - " + _request.getHttpURI()); LOG.debug("{} handle enter", this); } @@ -325,7 +325,7 @@ public class HttpChannel implements Runnable if (e instanceof EofException) LOG.debug(e); else - LOG.warn(String.valueOf(_request.getUri()), e); + LOG.warn(String.valueOf(_request.getHttpURI()), e); _state.error(e); _request.setHandled(true); handleException(e); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 7df3856d625..ae8c6143441 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -51,7 +51,6 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl private boolean _expect100Continue = false; private boolean _expect102Processing = false; - private final HttpURI _uri = new HttpURI(); private final MetaData.Request _metadata = new MetaData.Request(); @@ -60,7 +59,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl super(connector,config,endPoint,transport,input); _httpConnection = httpConnection; _metadata.setFields(_fields); - _metadata.setURI(_uri); + _metadata.setURI(new HttpURI()); } @Override @@ -70,7 +69,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl _expect = false; _expect100Continue = false; _expect102Processing = false; - _uri.clear(); + _metadata.getURI().clear(); _connection=null; _fields.clear(); } @@ -91,7 +90,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl public boolean startRequest(String method, String uri, HttpVersion version) { _metadata.setMethod(method); - _uri.parse(uri); + _metadata.getURI().parse(uri); _metadata.setHttpVersion(version); _expect = false; _expect100Continue = false; @@ -123,10 +122,10 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl break; case HOST: - if (!_uri.isAbsolute() && field instanceof HostPortHttpField) + if (!_metadata.getURI().isAbsolute() && field instanceof HostPortHttpField) { HostPortHttpField hp = (HostPortHttpField)field; - _uri.setAuthority(hp.getHost(),hp.getPort()); + _metadata.getURI().setAuthority(hp.getHost(),hp.getPort()); } break; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 5e5efea1890..43bc0f2dc1e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -128,6 +128,9 @@ public class Request implements HttpServletRequest private static final Logger LOG = Log.getLogger(Request.class); private static final Collection<Locale> __defaultLocale = Collections.singleton(Locale.getDefault()); private static final int __NONE = 0, _STREAM = 1, __READER = 2; + + private static final MultiMap<String> NO_PARAMS = new MultiMap<>(); + private final HttpChannel _channel; private final List<ServletRequestAttributeListener> _requestAttributeListeners=new ArrayList<>(); @@ -208,32 +211,32 @@ public class Request implements HttpServletRequest // Extract query string parameters; these may be replaced by a forward() // and may have already been extracted by mergeQueryParameters(). if (_queryParameters == null) - _queryParameters = extractQueryParameters(); + extractQueryParameters(); // Extract content parameters; these cannot be replaced by a forward() // once extracted and may have already been extracted by getParts() or // by a processing happening after a form-based authentication. if (_contentParameters == null) - _contentParameters = extractContentParameters(); + extractContentParameters(); - _parameters = restoreParameters(); + restoreParameters(); } /* ------------------------------------------------------------ */ - private MultiMap<String> extractQueryParameters() + private void extractQueryParameters() { - MultiMap<String> result = new MultiMap<>(); - if (_metadata.getURI() != null && _metadata.getURI().hasQuery()) + if (_metadata.getURI() == null || !_metadata.getURI().hasQuery()) + _queryParameters=NO_PARAMS; + else { + _queryParameters = new MultiMap<>(); if (_queryEncoding == null) - { - _metadata.getURI().decodeQueryTo(result); - } + _metadata.getURI().decodeQueryTo(_queryParameters); else { try { - _metadata.getURI().decodeQueryTo(result, _queryEncoding); + _metadata.getURI().decodeQueryTo(_queryParameters, _queryEncoding); } catch (UnsupportedEncodingException e) { @@ -244,17 +247,17 @@ public class Request implements HttpServletRequest } } } - return result; } /* ------------------------------------------------------------ */ - private MultiMap<String> extractContentParameters() + private void extractContentParameters() { - MultiMap<String> result = new MultiMap<>(); - String contentType = getContentType(); - if (contentType != null && !contentType.isEmpty()) + if (contentType == null || contentType.isEmpty()) + _contentParameters=NO_PARAMS; + else { + _contentParameters=new MultiMap<>(); contentType = HttpFields.valueParameters(contentType, null); int contentLength = getContentLength(); if (contentLength != 0) @@ -262,18 +265,17 @@ public class Request implements HttpServletRequest if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _inputState == __NONE && (HttpMethod.POST.is(getMethod()) || HttpMethod.PUT.is(getMethod()))) { - extractFormParameters(result); + extractFormParameters(_contentParameters); } else if (contentType.startsWith("multipart/form-data") && getAttribute(__MULTIPART_CONFIG_ELEMENT) != null && _multiPartInputStream == null) { - extractMultipartParameters(result); + extractMultipartParameters(_contentParameters); } } } - - return result; + } /* ------------------------------------------------------------ */ @@ -841,7 +843,7 @@ public class Request implements HttpServletRequest if (!_paramsExtracted) extractParameters(); if (_parameters == null) - _parameters = restoreParameters(); + restoreParameters(); return _parameters.getValue(name,0); } @@ -855,7 +857,7 @@ public class Request implements HttpServletRequest if (!_paramsExtracted) extractParameters(); if (_parameters == null) - _parameters = restoreParameters(); + restoreParameters(); return Collections.unmodifiableMap(_parameters.toStringArrayMap()); } @@ -869,7 +871,7 @@ public class Request implements HttpServletRequest if (!_paramsExtracted) extractParameters(); if (_parameters == null) - _parameters = restoreParameters(); + restoreParameters(); return Collections.enumeration(_parameters.keySet()); } @@ -883,38 +885,50 @@ public class Request implements HttpServletRequest if (!_paramsExtracted) extractParameters(); if (_parameters == null) - _parameters = restoreParameters(); + restoreParameters(); List<String> vals = _parameters.getValues(name); if (vals == null) return null; return vals.toArray(new String[vals.size()]); } - private MultiMap<String> restoreParameters() + /* ------------------------------------------------------------ */ + private void restoreParameters() { - MultiMap<String> result = new MultiMap<>(); if (_queryParameters == null) - _queryParameters = extractQueryParameters(); - result.addAllValues(_queryParameters); - result.addAllValues(_contentParameters); - return result; + extractQueryParameters(); + + if (_queryParameters==NO_PARAMS || _queryParameters.size()==0) + _parameters=_contentParameters; + else if (_contentParameters==NO_PARAMS || _contentParameters.size()==0) + _parameters=_queryParameters; + else + { + _parameters = new MultiMap<>(); + _parameters.addAllValues(_queryParameters); + _parameters.addAllValues(_contentParameters); + } } + /* ------------------------------------------------------------ */ public MultiMap<String> getQueryParameters() { return _queryParameters; } + /* ------------------------------------------------------------ */ public void setQueryParameters(MultiMap<String> queryParameters) { _queryParameters = queryParameters; } + /* ------------------------------------------------------------ */ public void setContentParameters(MultiMap<String> contentParameters) { _contentParameters = contentParameters; } + /* ------------------------------------------------------------ */ public void resetParameters() { _parameters = null; @@ -1408,11 +1422,20 @@ public class Request implements HttpServletRequest /** * @return Returns the uri. */ - public HttpURI getUri() + public HttpURI getHttpURI() { return _metadata.getURI(); } + /* ------------------------------------------------------------ */ + /** + * @param old_uri + */ + public void setHttpURI(HttpURI uri) + { + _metadata.setURI(uri); + } + /* ------------------------------------------------------------ */ public UserIdentity getUserIdentity() { @@ -2161,24 +2184,35 @@ public class Request implements HttpServletRequest _authentication=Authentication.UNAUTHENTICATED; } - public void mergeQueryParameters(String newQuery, boolean updateQueryString) + /* ------------------------------------------------------------ */ + public void mergeQueryParameters(String oldQuery,String newQuery, boolean updateQueryString) { - MultiMap<String> newQueryParams = new MultiMap<>(); + // TODO This is seriously ugly + + MultiMap<String> newQueryParams = null; // Have to assume ENCODING because we can't know otherwise. - UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING); - - MultiMap<String> oldQueryParams = _queryParameters; - if (oldQueryParams == null && getQueryString() != null) + if (newQuery!=null) { - oldQueryParams = new MultiMap<>(); - UrlEncoded.decodeTo(getQueryString(), oldQueryParams, getQueryEncoding()); + newQueryParams = new MultiMap<>(); + UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING); } - MultiMap<String> mergedQueryParams = newQueryParams; - if (oldQueryParams != null) + MultiMap<String> oldQueryParams = _queryParameters; + if (oldQueryParams == null && oldQuery != null) + { + oldQueryParams = new MultiMap<>(); + UrlEncoded.decodeTo(oldQuery, oldQueryParams, getQueryEncoding()); + } + + MultiMap<String> mergedQueryParams; + if (newQueryParams==null || newQueryParams.size()==0) + mergedQueryParams=oldQueryParams==null?NO_PARAMS:oldQueryParams; + else if (oldQueryParams==null || oldQueryParams.size()==0) + mergedQueryParams=newQueryParams==null?NO_PARAMS:newQueryParams; + else { // Parameters values are accumulated. - mergedQueryParams = new MultiMap<>(newQueryParams); + mergedQueryParams=new MultiMap<>(newQueryParams); mergedQueryParams.addAllValues(oldQueryParams); } @@ -2189,13 +2223,19 @@ public class Request implements HttpServletRequest { // Build the new merged query string, parameters in the // new query string hide parameters in the old query string. - StringBuilder mergedQuery = new StringBuilder(newQuery); + StringBuilder mergedQuery = new StringBuilder(); + if (newQuery!=null) + mergedQuery.append(newQuery); for (Map.Entry<String, List<String>> entry : mergedQueryParams.entrySet()) { - if (newQueryParams.containsKey(entry.getKey())) + if (newQueryParams!=null && newQueryParams.containsKey(entry.getKey())) continue; for (String value : entry.getValue()) - mergedQuery.append("&").append(entry.getKey()).append("=").append(value); + { + if (mergedQuery.length()>0) + mergedQuery.append("&"); + mergedQuery.append(entry.getKey()).append("=").append(value); + } } setQueryString(mergedQuery.toString()); @@ -2227,5 +2267,6 @@ public class Request implements HttpServletRequest throw new ServletException(e); } } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index bf77f1f314e..6128662575a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -519,11 +519,12 @@ public class Server extends HandlerWrapper implements Attributes { // this is a dispatch with a path ServletContext context=event.getServletContext(); + String query=baseRequest.getQueryString(); baseRequest.setURIPathQuery(URIUtil.addPaths(context==null?null:context.getContextPath(), path)); - HttpURI uri = baseRequest.getUri(); + HttpURI uri = baseRequest.getHttpURI(); baseRequest.setPathInfo(uri.getDecodedPath()); if (uri.getQuery()!=null) - baseRequest.mergeQueryParameters(uri.getQuery(), true); //we have to assume dispatch path and query are UTF8 + baseRequest.mergeQueryParameters(query,uri.getQuery(), true); //we have to assume dispatch path and query are UTF8 } final String target=baseRequest.getPathInfo(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index ed6efd1b654..8208110f8de 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -64,6 +64,7 @@ import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.server.ClassLoaderDump; import org.eclipse.jetty.server.Dispatcher; @@ -1933,21 +1934,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu try { - String query = null; - int q = 0; - if ((q = uriInContext.indexOf('?')) > 0) - { - query = uriInContext.substring(q + 1); - uriInContext = uriInContext.substring(0,q); - } + HttpURI uri = new HttpURI(null,null,0,uriInContext); + + String pathInfo=URIUtil.canonicalPath(uri.getDecodedPath()); + if (pathInfo==null) + return null; - String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext)); - if (pathInContext!=null) - { - String uri = URIUtil.addPaths(getContextPath(),uriInContext); - ContextHandler context = ContextHandler.this; - return new Dispatcher(context,uri,pathInContext,query); - } + String contextPath=getContextPath(); + if (contextPath!=null && contextPath.length()>0) + uri.setPath(URIUtil.addPaths(contextPath,uri.getPath())); + + return new Dispatcher(ContextHandler.this,uri,pathInfo); } catch (Exception e) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java index 0ed72612fc4..143a8e858e7 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java @@ -65,7 +65,7 @@ public class DebugHandler extends HandlerWrapper implements Connection.Listener boolean retry=false; String name=(String)request.getAttribute("org.eclipse.jetty.thread.name"); if (name==null) - name=old_name+":"+baseRequest.getScheme()+"://"+baseRequest.getLocalAddr()+":"+baseRequest.getLocalPort()+baseRequest.getUri(); + name=old_name+":"+baseRequest.getScheme()+"://"+baseRequest.getLocalAddr()+":"+baseRequest.getLocalPort()+baseRequest.getHttpURI(); else retry=true; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java index ab25084f996..2b8c8c54dba 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java @@ -202,7 +202,7 @@ public class AsyncStressTest long resume_after=-1; long complete_after=-1; - final String uri=baseRequest.getUri().toString(); + final String uri=baseRequest.getHttpURI().toString(); if (request.getParameter("read")!=null) read_before=Integer.parseInt(request.getParameter("read")); @@ -255,7 +255,7 @@ public class AsyncStressTest Request br=(Request)asyncContext.getRequest(); System.err.println("\n"+e.toString()); System.err.println(baseRequest+"=="+br); - System.err.println(uri+"=="+br.getUri()); + System.err.println(uri+"=="+br.getHttpURI()); System.err.println(asyncContext+"=="+br.getHttpChannelState()); LOG.warn(e); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java index b8e54dafa59..891cc0849a7 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java @@ -41,7 +41,7 @@ public class DispatcherForwardTest private LocalConnector connector; private HttpServlet servlet1; private HttpServlet servlet2; - private List<Exception> failures = new ArrayList<>(); + private List<Throwable> failures = new ArrayList<>(); public void prepare() throws Exception { @@ -57,9 +57,9 @@ public class DispatcherForwardTest } @After - public void dispose() throws Exception + public void dispose() throws Throwable { - for (Exception failure : failures) + for (Throwable failure : failures) throw failure; server.stop(); } @@ -67,8 +67,14 @@ public class DispatcherForwardTest // Replacement for Assert that allows to check failures after the response has been sent. private <S> void checkThat(S item, Matcher<S> matcher) { - if (!matcher.matches(item)) - failures.add(new Exception()); + try + { + Assert.assertThat(item,matcher); + } + catch(Throwable th) + { + failures.add(th); + } } @Test @@ -85,12 +91,12 @@ public class DispatcherForwardTest @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); req.getRequestDispatcher("/two").forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); } }; servlet2 = new HttpServlet() @@ -98,8 +104,8 @@ public class DispatcherForwardTest @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); } }; @@ -130,13 +136,13 @@ public class DispatcherForwardTest @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); req.getRequestDispatcher("/two?" + query2).forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); - checkThat("2", Matchers.equalTo(req.getParameter("b"))); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); + checkThat(req.getParameter("b"),Matchers.equalTo("2")); } }; servlet2 = new HttpServlet() @@ -144,9 +150,9 @@ public class DispatcherForwardTest @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query3, Matchers.equalTo(req.getQueryString())); - checkThat("3", Matchers.equalTo(req.getParameter("a"))); - checkThat("2", Matchers.equalTo(req.getParameter("b"))); + checkThat(req.getQueryString(),Matchers.equalTo(query3)); + checkThat(req.getParameter("a"),Matchers.equalTo("3")); + checkThat(req.getParameter("b"),Matchers.equalTo("2")); } }; @@ -177,12 +183,12 @@ public class DispatcherForwardTest @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); req.getRequestDispatcher("/two?" + query2).forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); } }; servlet2 = new HttpServlet() @@ -190,9 +196,9 @@ public class DispatcherForwardTest @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query3, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); - checkThat("2", Matchers.equalTo(req.getParameter("b"))); + checkThat(req.getQueryString(),Matchers.equalTo(query3)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); + checkThat(req.getParameter("b"),Matchers.equalTo("2")); } }; @@ -222,11 +228,11 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); req.getRequestDispatcher("/two").forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); String[] values = req.getParameterValues("a"); checkThat(values, Matchers.notNullValue()); checkThat(2, Matchers.equalTo(values.length)); @@ -238,7 +244,7 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); String[] values = req.getParameterValues("a"); checkThat(values, Matchers.notNullValue()); checkThat(2, Matchers.equalTo(values.length)); @@ -276,11 +282,11 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); req.getRequestDispatcher("/two?" + query2).forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); String[] values = req.getParameterValues("a"); checkThat(values, Matchers.notNullValue()); checkThat(2, Matchers.equalTo(values.length)); @@ -292,7 +298,7 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query2, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query2)); String[] values = req.getParameterValues("a"); checkThat(values, Matchers.notNullValue()); checkThat(3, Matchers.equalTo(values.length)); @@ -331,13 +337,13 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); req.getRequestDispatcher("/two?" + query2).forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); - checkThat("2", Matchers.equalTo(req.getParameter("b"))); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); + checkThat(req.getParameter("b"),Matchers.equalTo("2")); checkThat(req.getParameter("c"), Matchers.nullValue()); } }; @@ -346,10 +352,10 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query3, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); - checkThat("2", Matchers.equalTo(req.getParameter("b"))); - checkThat("3", Matchers.equalTo(req.getParameter("c"))); + checkThat(req.getQueryString(),Matchers.equalTo(query3)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); + checkThat(req.getParameter("b"),Matchers.equalTo("2")); + checkThat(req.getParameter("c"),Matchers.equalTo("3")); } }; @@ -385,15 +391,15 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); - checkThat("2", Matchers.equalTo(req.getParameter("b"))); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); + checkThat(req.getParameter("b"),Matchers.equalTo("2")); req.getRequestDispatcher("/two?" + query2).forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); - checkThat("2", Matchers.equalTo(req.getParameter("b"))); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); + checkThat(req.getParameter("b"),Matchers.equalTo("2")); checkThat(req.getParameter("c"), Matchers.nullValue()); } }; @@ -402,10 +408,10 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query3, Matchers.equalTo(req.getQueryString())); - checkThat("1", Matchers.equalTo(req.getParameter("a"))); - checkThat("2", Matchers.equalTo(req.getParameter("b"))); - checkThat("3", Matchers.equalTo(req.getParameter("c"))); + checkThat(req.getQueryString(),Matchers.equalTo(query3)); + checkThat(req.getParameter("a"),Matchers.equalTo("1")); + checkThat(req.getParameter("b"),Matchers.equalTo("2")); + checkThat(req.getParameter("c"),Matchers.equalTo("3")); } }; @@ -433,11 +439,11 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); req.getRequestDispatcher("/two").forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); checkThat(req.getParameter("c"), Matchers.nullValue()); } }; @@ -446,7 +452,7 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); ServletInputStream input = req.getInputStream(); for (int i = 0; i < form.length(); ++i) checkThat(form.charAt(i) & 0xFFFF, Matchers.equalTo(input.read())); @@ -479,11 +485,11 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); req.getRequestDispatcher("/two?" + query2).forward(req, resp); - checkThat(query1, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query1)); checkThat(req.getParameter("c"), Matchers.nullValue()); } }; @@ -492,7 +498,7 @@ public class DispatcherForwardTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - checkThat(query3, Matchers.equalTo(req.getQueryString())); + checkThat(req.getQueryString(),Matchers.equalTo(query3)); ServletInputStream input = req.getInputStream(); for (int i = 0; i < form.length(); ++i) checkThat(form.charAt(i) & 0xFFFF, Matchers.equalTo(input.read())); diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java index 4954a84928a..7073296fddb 100644 --- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java +++ b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java @@ -109,7 +109,7 @@ public class HttpClientCustomProxyTest public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); - if (!URI.create(baseRequest.getUri().toString()).isAbsolute()) + if (!URI.create(baseRequest.getHttpURI().toString()).isAbsolute()) response.setStatus(HttpServletResponse.SC_USE_PROXY); else if (serverHost.equals(request.getServerName())) response.setStatus(status); From a1696c013942d9a2d706e345152b02ee2a8afcb4 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 25 Jul 2014 19:38:16 +1000 Subject: [PATCH 155/269] updates for hpack huffman and examples --- .../jetty/http2/hpack/HpackContext.java | 128 ++--- .../jetty/http2/hpack/HpackDecoder.java | 12 +- .../eclipse/jetty/http2/hpack/Huffman.java | 515 +++++++++--------- .../jetty/http2/hpack/HpackDecoderTest.java | 22 +- .../jetty/http2/hpack/HpackPerfTest.java | 4 +- .../jetty/http2/hpack/HuffmanTest.java | 16 +- .../test/resources/jetty-logging.properties | 2 +- 7 files changed, 347 insertions(+), 352 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 68f7f9882b8..d0ac96b2135 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -41,68 +41,67 @@ public class HpackContext public static final String[][] STATIC_TABLE = { {null,null}, - /* 1 */ {":authority" ,null}, - /* 2 */ {":method" ,"GET"}, - /* 3 */ {":method" ,"POST"}, - /* 4 */ {":path" ,"/"}, - /* 5 */ {":path" ,"/index.html"}, - /* 6 */ {":scheme" ,"http"}, - /* 7 */ {":scheme" ,"https"}, - /* 8 */ {":status" ,"200"}, - /* 9 */ {":status" ,"204"}, - /* 10 */ {":status" ,"206"}, - /* 11 */ {":status" ,"304"}, - /* 12 */ {":status" ,"400"}, - /* 13 */ {":status" ,"404"}, - /* 14 */ {":status" ,"500"}, - /* 15 */ {"accept-charset" ,null}, - /* 16 */ {"accept-encoding" ,null}, - /* 17 */ {"accept-language" ,null}, - /* 18 */ {"accept-ranges" ,null}, - /* 19 */ {"accept" ,null}, - /* 20 */ {"access-control-allow-origin" ,null}, - /* 21 */ {"age" ,null}, - /* 22 */ {"allow" ,null}, - /* 23 */ {"authorization" ,null}, - /* 24 */ {"cache-control" ,null}, - /* 25 */ {"content-disposition" ,null}, - /* 26 */ {"content-encoding" ,null}, - /* 27 */ {"content-language" ,null}, - /* 28 */ {"content-length" ,null}, - /* 29 */ {"content-location" ,null}, - /* 30 */ {"content-range" ,null}, - /* 31 */ {"content-type" ,null}, - /* 32 */ {"cookie" ,null}, - /* 33 */ {"date" ,null}, - /* 34 */ {"etag" ,null}, - /* 35 */ {"expect" ,null}, - /* 36 */ {"expires" ,null}, - /* 37 */ {"from" ,null}, - /* 38 */ {"host" ,null}, - /* 39 */ {"if-match" ,null}, - /* 40 */ {"if-modified-since" ,null}, - /* 41 */ {"if-none-match" ,null}, - /* 42 */ {"if-range" ,null}, - /* 43 */ {"if-unmodified-since" ,null}, - /* 44 */ {"last-modified" ,null}, - /* 45 */ {"link" ,null}, - /* 46 */ {"location" ,null}, - /* 47 */ {"max-forwards" ,null}, - /* 48 */ {"proxy-authenticate" ,null}, - /* 49 */ {"proxy-authorization" ,null}, - /* 50 */ {"range" ,null}, - /* 51 */ {"referer" ,null}, - /* 52 */ {"refresh" ,null}, - /* 53 */ {"retry-after" ,null}, - /* 54 */ {"server" ,null}, - /* 55 */ {"set-cookie" ,null}, - /* 56 */ {"strict-transport-security" ,null}, - /* 57 */ {"transfer-encoding" ,null}, - /* 58 */ {"user-agent" ,null}, - /* 59 */ {"vary" ,null}, - /* 60 */ {"via" ,null}, - /* 61 */ {"www-authenticate" ,null}, - + /* 1 */ {":authority",null}, + /* 2 */ {":method","GET"}, + /* 3 */ {":method","POST"}, + /* 4 */ {":path","/"}, + /* 5 */ {":path","/index.html"}, + /* 6 */ {":scheme","http"}, + /* 7 */ {":scheme","https"}, + /* 8 */ {":status","200"}, + /* 9 */ {":status","204"}, + /* 10 */ {":status","206"}, + /* 11 */ {":status","304"}, + /* 12 */ {":status","400"}, + /* 13 */ {":status","404"}, + /* 14 */ {":status","500"}, + /* 15 */ {"accept-charset",null}, + /* 16 */ {"accept-encoding","gzip, deflate"}, + /* 17 */ {"accept-language",null}, + /* 18 */ {"accept-ranges",null}, + /* 19 */ {"accept",null}, + /* 20 */ {"access-control-allow-origin",null}, + /* 21 */ {"age",null}, + /* 22 */ {"allow",null}, + /* 23 */ {"authorization",null}, + /* 24 */ {"cache-control",null}, + /* 25 */ {"content-disposition",null}, + /* 26 */ {"content-encoding",null}, + /* 27 */ {"content-language",null}, + /* 28 */ {"content-length",null}, + /* 29 */ {"content-location",null}, + /* 30 */ {"content-range",null}, + /* 31 */ {"content-type",null}, + /* 32 */ {"cookie",null}, + /* 33 */ {"date",null}, + /* 34 */ {"etag",null}, + /* 35 */ {"expect",null}, + /* 36 */ {"expires",null}, + /* 37 */ {"from",null}, + /* 38 */ {"host",null}, + /* 39 */ {"if-match",null}, + /* 40 */ {"if-modified-since",null}, + /* 41 */ {"if-none-match",null}, + /* 42 */ {"if-range",null}, + /* 43 */ {"if-unmodified-since",null}, + /* 44 */ {"last-modified",null}, + /* 45 */ {"link",null}, + /* 46 */ {"location",null}, + /* 47 */ {"max-forwards",null}, + /* 48 */ {"proxy-authenticate",null}, + /* 49 */ {"proxy-authorization",null}, + /* 50 */ {"range",null}, + /* 51 */ {"referer",null}, + /* 52 */ {"refresh",null}, + /* 53 */ {"retry-after",null}, + /* 54 */ {"server",null}, + /* 55 */ {"set-cookie",null}, + /* 56 */ {"strict-transport-security",null}, + /* 57 */ {"transfer-encoding",null}, + /* 58 */ {"user-agent",null}, + /* 59 */ {"vary",null}, + /* 60 */ {"via",null}, + /* 61 */ {"www-authenticate",null}, }; private static final Map<HttpField,Entry> __staticFieldMap = new HashMap<>(); @@ -288,6 +287,11 @@ public class HpackContext } } + @Override + public String toString() + { + return String.format("HpackContext@%x{%s}",hashCode(),_headerTable); + } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index c19858ed639..d80b5f550d4 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -82,7 +82,11 @@ public class HpackDecoder // indexed int index = NBitInteger.decode(buffer,7); Entry entry=_context.get(index); - if (entry.isStatic()) + if (entry==null) + { + throw new BadMessageException("Unknown index "+index); + } + else if (entry.isStatic()) { if (LOG.isDebugEnabled()) LOG.debug("decode IdxStatic {}",entry); @@ -240,4 +244,10 @@ public class HpackDecoder builder.append((char)(0x7f&array[i])); return builder.toString(); } + + @Override + public String toString() + { + return String.format("HpackDecoder@%x{%s}",hashCode(),_context); + } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java index a80e193d9e3..d8cbc5f2d32 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java @@ -27,264 +27,263 @@ public class Huffman // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C static final int[][] CODES = { - /* ( 0) |11111111|11111111|11101110|10 */ {0x3ffffba,26}, - /* ( 1) |11111111|11111111|11101110|11 */ {0x3ffffbb,26}, - /* ( 2) |11111111|11111111|11101111|00 */ {0x3ffffbc,26}, - /* ( 3) |11111111|11111111|11101111|01 */ {0x3ffffbd,26}, - /* ( 4) |11111111|11111111|11101111|10 */ {0x3ffffbe,26}, - /* ( 5) |11111111|11111111|11101111|11 */ {0x3ffffbf,26}, - /* ( 6) |11111111|11111111|11110000|00 */ {0x3ffffc0,26}, - /* ( 7) |11111111|11111111|11110000|01 */ {0x3ffffc1,26}, - /* ( 8) |11111111|11111111|11110000|10 */ {0x3ffffc2,26}, - /* ( 9) |11111111|11111111|11110000|11 */ {0x3ffffc3,26}, - /* ( 10) |11111111|11111111|11110001|00 */ {0x3ffffc4,26}, - /* ( 11) |11111111|11111111|11110001|01 */ {0x3ffffc5,26}, - /* ( 12) |11111111|11111111|11110001|10 */ {0x3ffffc6,26}, - /* ( 13) |11111111|11111111|11110001|11 */ {0x3ffffc7,26}, - /* ( 14) |11111111|11111111|11110010|00 */ {0x3ffffc8,26}, - /* ( 15) |11111111|11111111|11110010|01 */ {0x3ffffc9,26}, - /* ( 16) |11111111|11111111|11110010|10 */ {0x3ffffca,26}, - /* ( 17) |11111111|11111111|11110010|11 */ {0x3ffffcb,26}, - /* ( 18) |11111111|11111111|11110011|00 */ {0x3ffffcc,26}, - /* ( 19) |11111111|11111111|11110011|01 */ {0x3ffffcd,26}, - /* ( 20) |11111111|11111111|11110011|10 */ {0x3ffffce,26}, - /* ( 21) |11111111|11111111|11110011|11 */ {0x3ffffcf,26}, - /* ( 22) |11111111|11111111|11110100|00 */ {0x3ffffd0,26}, - /* ( 23) |11111111|11111111|11110100|01 */ {0x3ffffd1,26}, - /* ( 24) |11111111|11111111|11110100|10 */ {0x3ffffd2,26}, - /* ( 25) |11111111|11111111|11110100|11 */ {0x3ffffd3,26}, - /* ( 26) |11111111|11111111|11110101|00 */ {0x3ffffd4,26}, - /* ( 27) |11111111|11111111|11110101|01 */ {0x3ffffd5,26}, - /* ( 28) |11111111|11111111|11110101|10 */ {0x3ffffd6,26}, - /* ( 29) |11111111|11111111|11110101|11 */ {0x3ffffd7,26}, - /* ( 30) |11111111|11111111|11110110|00 */ {0x3ffffd8,26}, - /* ( 31) |11111111|11111111|11110110|01 */ {0x3ffffd9,26}, - /*' ' ( 32) |00110 */ {0x6, 5}, - /*'!' ( 33) |11111111|11100 */ {0x1ffc,13}, - /*'"' ( 34) |11111000|0 */ {0x1f0, 9}, - /*'#' ( 35) |11111111|111100 */ {0x3ffc,14}, - /*'$' ( 36) |11111111|1111100 */ {0x7ffc,15}, - /*'%' ( 37) |011110 */ {0x1e, 6}, - /*'&' ( 38) |1100100 */ {0x64, 7}, - /*''' ( 39) |11111111|11101 */ {0x1ffd,13}, - /*'(' ( 40) |11111110|10 */ {0x3fa,10}, - /*')' ( 41) |11111000|1 */ {0x1f1, 9}, - /*'*' ( 42) |11111110|11 */ {0x3fb,10}, - /*'+' ( 43) |11111111|00 */ {0x3fc,10}, - /*',' ( 44) |1100101 */ {0x65, 7}, - /*'-' ( 45) |1100110 */ {0x66, 7}, - /*'.' ( 46) |011111 */ {0x1f, 6}, - /*'/' ( 47) |00111 */ {0x7, 5}, - /*'0' ( 48) |0000 */ {0x0, 4}, - /*'1' ( 49) |0001 */ {0x1, 4}, - /*'2' ( 50) |0010 */ {0x2, 4}, - /*'3' ( 51) |01000 */ {0x8, 5}, - /*'4' ( 52) |100000 */ {0x20, 6}, - /*'5' ( 53) |100001 */ {0x21, 6}, - /*'6' ( 54) |100010 */ {0x22, 6}, - /*'7' ( 55) |100011 */ {0x23, 6}, - /*'8' ( 56) |100100 */ {0x24, 6}, - /*'9' ( 57) |100101 */ {0x25, 6}, - /*':' ( 58) |100110 */ {0x26, 6}, - /*';' ( 59) |11101100| */ {0xec, 8}, - /*'<' ( 60) |11111111|11111110|0 */ {0x1fffc,17}, - /*'=' ( 61) |100111 */ {0x27, 6}, - /*'>' ( 62) |11111111|1111101 */ {0x7ffd,15}, - /*'?' ( 63) |11111111|01 */ {0x3fd,10}, - /*'@' ( 64) |11111111|1111110 */ {0x7ffe,15}, - /*'A' ( 65) |1100111 */ {0x67, 7}, - /*'B' ( 66) |11101101| */ {0xed, 8}, - /*'C' ( 67) |11101110| */ {0xee, 8}, - /*'D' ( 68) |1101000 */ {0x68, 7}, - /*'E' ( 69) |11101111| */ {0xef, 8}, - /*'F' ( 70) |1101001 */ {0x69, 7}, - /*'G' ( 71) |1101010 */ {0x6a, 7}, - /*'H' ( 72) |11111001|0 */ {0x1f2, 9}, - /*'I' ( 73) |11110000| */ {0xf0, 8}, - /*'J' ( 74) |11111001|1 */ {0x1f3, 9}, - /*'K' ( 75) |11111010|0 */ {0x1f4, 9}, - /*'L' ( 76) |11111010|1 */ {0x1f5, 9}, - /*'M' ( 77) |1101011 */ {0x6b, 7}, - /*'N' ( 78) |1101100 */ {0x6c, 7}, - /*'O' ( 79) |11110001| */ {0xf1, 8}, - /*'P' ( 80) |11110010| */ {0xf2, 8}, - /*'Q' ( 81) |11111011|0 */ {0x1f6, 9}, - /*'R' ( 82) |11111011|1 */ {0x1f7, 9}, - /*'S' ( 83) |1101101 */ {0x6d, 7}, - /*'T' ( 84) |101000 */ {0x28, 6}, - /*'U' ( 85) |11110011| */ {0xf3, 8}, - /*'V' ( 86) |11111100|0 */ {0x1f8, 9}, - /*'W' ( 87) |11111100|1 */ {0x1f9, 9}, - /*'X' ( 88) |11110100| */ {0xf4, 8}, - /*'Y' ( 89) |11111101|0 */ {0x1fa, 9}, - /*'Z' ( 90) |11111101|1 */ {0x1fb, 9}, - /*'[' ( 91) |11111111|100 */ {0x7fc,11}, - /*'\' ( 92) |11111111|11111111|11110110|10 */ {0x3ffffda,26}, - /*']' ( 93) |11111111|101 */ {0x7fd,11}, - /*'^' ( 94) |11111111|111101 */ {0x3ffd,14}, - /*'_' ( 95) |1101110 */ {0x6e, 7}, - /*'`' ( 96) |11111111|11111111|10 */ {0x3fffe,18}, - /*'a' ( 97) |01001 */ {0x9, 5}, - /*'b' ( 98) |1101111 */ {0x6f, 7}, - /*'c' ( 99) |01010 */ {0xa, 5}, - /*'d' (100) |101001 */ {0x29, 6}, - /*'e' (101) |01011 */ {0xb, 5}, - /*'f' (102) |1110000 */ {0x70, 7}, - /*'g' (103) |101010 */ {0x2a, 6}, - /*'h' (104) |101011 */ {0x2b, 6}, - /*'i' (105) |01100 */ {0xc, 5}, - /*'j' (106) |11110101| */ {0xf5, 8}, - /*'k' (107) |11110110| */ {0xf6, 8}, - /*'l' (108) |101100 */ {0x2c, 6}, - /*'m' (109) |101101 */ {0x2d, 6}, - /*'n' (110) |101110 */ {0x2e, 6}, - /*'o' (111) |01101 */ {0xd, 5}, - /*'p' (112) |101111 */ {0x2f, 6}, - /*'q' (113) |11111110|0 */ {0x1fc, 9}, - /*'r' (114) |110000 */ {0x30, 6}, - /*'s' (115) |110001 */ {0x31, 6}, - /*'t' (116) |01110 */ {0xe, 5}, - /*'u' (117) |1110001 */ {0x71, 7}, - /*'v' (118) |1110010 */ {0x72, 7}, - /*'w' (119) |1110011 */ {0x73, 7}, - /*'x' (120) |1110100 */ {0x74, 7}, - /*'y' (121) |1110101 */ {0x75, 7}, - /*'z' (122) |11110111| */ {0xf7, 8}, - /*'{' (123) |11111111|11111110|1 */ {0x1fffd,17}, - /*'|' (124) |11111111|1100 */ {0xffc,12}, - /*'}' (125) |11111111|11111111|0 */ {0x1fffe,17}, - /*'~' (126) |11111111|1101 */ {0xffd,12}, - /* (127) |11111111|11111111|11110110|11 */ {0x3ffffdb,26}, - /* (128) |11111111|11111111|11110111|00 */ {0x3ffffdc,26}, - /* (129) |11111111|11111111|11110111|01 */ {0x3ffffdd,26}, - /* (130) |11111111|11111111|11110111|10 */ {0x3ffffde,26}, - /* (131) |11111111|11111111|11110111|11 */ {0x3ffffdf,26}, - /* (132) |11111111|11111111|11111000|00 */ {0x3ffffe0,26}, - /* (133) |11111111|11111111|11111000|01 */ {0x3ffffe1,26}, - /* (134) |11111111|11111111|11111000|10 */ {0x3ffffe2,26}, - /* (135) |11111111|11111111|11111000|11 */ {0x3ffffe3,26}, - /* (136) |11111111|11111111|11111001|00 */ {0x3ffffe4,26}, - /* (137) |11111111|11111111|11111001|01 */ {0x3ffffe5,26}, - /* (138) |11111111|11111111|11111001|10 */ {0x3ffffe6,26}, - /* (139) |11111111|11111111|11111001|11 */ {0x3ffffe7,26}, - /* (140) |11111111|11111111|11111010|00 */ {0x3ffffe8,26}, - /* (141) |11111111|11111111|11111010|01 */ {0x3ffffe9,26}, - /* (142) |11111111|11111111|11111010|10 */ {0x3ffffea,26}, - /* (143) |11111111|11111111|11111010|11 */ {0x3ffffeb,26}, - /* (144) |11111111|11111111|11111011|00 */ {0x3ffffec,26}, - /* (145) |11111111|11111111|11111011|01 */ {0x3ffffed,26}, - /* (146) |11111111|11111111|11111011|10 */ {0x3ffffee,26}, - /* (147) |11111111|11111111|11111011|11 */ {0x3ffffef,26}, - /* (148) |11111111|11111111|11111100|00 */ {0x3fffff0,26}, - /* (149) |11111111|11111111|11111100|01 */ {0x3fffff1,26}, - /* (150) |11111111|11111111|11111100|10 */ {0x3fffff2,26}, - /* (151) |11111111|11111111|11111100|11 */ {0x3fffff3,26}, - /* (152) |11111111|11111111|11111101|00 */ {0x3fffff4,26}, - /* (153) |11111111|11111111|11111101|01 */ {0x3fffff5,26}, - /* (154) |11111111|11111111|11111101|10 */ {0x3fffff6,26}, - /* (155) |11111111|11111111|11111101|11 */ {0x3fffff7,26}, - /* (156) |11111111|11111111|11111110|00 */ {0x3fffff8,26}, - /* (157) |11111111|11111111|11111110|01 */ {0x3fffff9,26}, - /* (158) |11111111|11111111|11111110|10 */ {0x3fffffa,26}, - /* (159) |11111111|11111111|11111110|11 */ {0x3fffffb,26}, - /* (160) |11111111|11111111|11111111|00 */ {0x3fffffc,26}, - /* (161) |11111111|11111111|11111111|01 */ {0x3fffffd,26}, - /* (162) |11111111|11111111|11111111|10 */ {0x3fffffe,26}, - /* (163) |11111111|11111111|11111111|11 */ {0x3ffffff,26}, - /* (164) |11111111|11111111|11000000|0 */ {0x1ffff80,25}, - /* (165) |11111111|11111111|11000000|1 */ {0x1ffff81,25}, - /* (166) |11111111|11111111|11000001|0 */ {0x1ffff82,25}, - /* (167) |11111111|11111111|11000001|1 */ {0x1ffff83,25}, - /* (168) |11111111|11111111|11000010|0 */ {0x1ffff84,25}, - /* (169) |11111111|11111111|11000010|1 */ {0x1ffff85,25}, - /* (170) |11111111|11111111|11000011|0 */ {0x1ffff86,25}, - /* (171) |11111111|11111111|11000011|1 */ {0x1ffff87,25}, - /* (172) |11111111|11111111|11000100|0 */ {0x1ffff88,25}, - /* (173) |11111111|11111111|11000100|1 */ {0x1ffff89,25}, - /* (174) |11111111|11111111|11000101|0 */ {0x1ffff8a,25}, - /* (175) |11111111|11111111|11000101|1 */ {0x1ffff8b,25}, - /* (176) |11111111|11111111|11000110|0 */ {0x1ffff8c,25}, - /* (177) |11111111|11111111|11000110|1 */ {0x1ffff8d,25}, - /* (178) |11111111|11111111|11000111|0 */ {0x1ffff8e,25}, - /* (179) |11111111|11111111|11000111|1 */ {0x1ffff8f,25}, - /* (180) |11111111|11111111|11001000|0 */ {0x1ffff90,25}, - /* (181) |11111111|11111111|11001000|1 */ {0x1ffff91,25}, - /* (182) |11111111|11111111|11001001|0 */ {0x1ffff92,25}, - /* (183) |11111111|11111111|11001001|1 */ {0x1ffff93,25}, - /* (184) |11111111|11111111|11001010|0 */ {0x1ffff94,25}, - /* (185) |11111111|11111111|11001010|1 */ {0x1ffff95,25}, - /* (186) |11111111|11111111|11001011|0 */ {0x1ffff96,25}, - /* (187) |11111111|11111111|11001011|1 */ {0x1ffff97,25}, - /* (188) |11111111|11111111|11001100|0 */ {0x1ffff98,25}, - /* (189) |11111111|11111111|11001100|1 */ {0x1ffff99,25}, - /* (190) |11111111|11111111|11001101|0 */ {0x1ffff9a,25}, - /* (191) |11111111|11111111|11001101|1 */ {0x1ffff9b,25}, - /* (192) |11111111|11111111|11001110|0 */ {0x1ffff9c,25}, - /* (193) |11111111|11111111|11001110|1 */ {0x1ffff9d,25}, - /* (194) |11111111|11111111|11001111|0 */ {0x1ffff9e,25}, - /* (195) |11111111|11111111|11001111|1 */ {0x1ffff9f,25}, - /* (196) |11111111|11111111|11010000|0 */ {0x1ffffa0,25}, - /* (197) |11111111|11111111|11010000|1 */ {0x1ffffa1,25}, - /* (198) |11111111|11111111|11010001|0 */ {0x1ffffa2,25}, - /* (199) |11111111|11111111|11010001|1 */ {0x1ffffa3,25}, - /* (200) |11111111|11111111|11010010|0 */ {0x1ffffa4,25}, - /* (201) |11111111|11111111|11010010|1 */ {0x1ffffa5,25}, - /* (202) |11111111|11111111|11010011|0 */ {0x1ffffa6,25}, - /* (203) |11111111|11111111|11010011|1 */ {0x1ffffa7,25}, - /* (204) |11111111|11111111|11010100|0 */ {0x1ffffa8,25}, - /* (205) |11111111|11111111|11010100|1 */ {0x1ffffa9,25}, - /* (206) |11111111|11111111|11010101|0 */ {0x1ffffaa,25}, - /* (207) |11111111|11111111|11010101|1 */ {0x1ffffab,25}, - /* (208) |11111111|11111111|11010110|0 */ {0x1ffffac,25}, - /* (209) |11111111|11111111|11010110|1 */ {0x1ffffad,25}, - /* (210) |11111111|11111111|11010111|0 */ {0x1ffffae,25}, - /* (211) |11111111|11111111|11010111|1 */ {0x1ffffaf,25}, - /* (212) |11111111|11111111|11011000|0 */ {0x1ffffb0,25}, - /* (213) |11111111|11111111|11011000|1 */ {0x1ffffb1,25}, - /* (214) |11111111|11111111|11011001|0 */ {0x1ffffb2,25}, - /* (215) |11111111|11111111|11011001|1 */ {0x1ffffb3,25}, - /* (216) |11111111|11111111|11011010|0 */ {0x1ffffb4,25}, - /* (217) |11111111|11111111|11011010|1 */ {0x1ffffb5,25}, - /* (218) |11111111|11111111|11011011|0 */ {0x1ffffb6,25}, - /* (219) |11111111|11111111|11011011|1 */ {0x1ffffb7,25}, - /* (220) |11111111|11111111|11011100|0 */ {0x1ffffb8,25}, - /* (221) |11111111|11111111|11011100|1 */ {0x1ffffb9,25}, - /* (222) |11111111|11111111|11011101|0 */ {0x1ffffba,25}, - /* (223) |11111111|11111111|11011101|1 */ {0x1ffffbb,25}, - /* (224) |11111111|11111111|11011110|0 */ {0x1ffffbc,25}, - /* (225) |11111111|11111111|11011110|1 */ {0x1ffffbd,25}, - /* (226) |11111111|11111111|11011111|0 */ {0x1ffffbe,25}, - /* (227) |11111111|11111111|11011111|1 */ {0x1ffffbf,25}, - /* (228) |11111111|11111111|11100000|0 */ {0x1ffffc0,25}, - /* (229) |11111111|11111111|11100000|1 */ {0x1ffffc1,25}, - /* (230) |11111111|11111111|11100001|0 */ {0x1ffffc2,25}, - /* (231) |11111111|11111111|11100001|1 */ {0x1ffffc3,25}, - /* (232) |11111111|11111111|11100010|0 */ {0x1ffffc4,25}, - /* (233) |11111111|11111111|11100010|1 */ {0x1ffffc5,25}, - /* (234) |11111111|11111111|11100011|0 */ {0x1ffffc6,25}, - /* (235) |11111111|11111111|11100011|1 */ {0x1ffffc7,25}, - /* (236) |11111111|11111111|11100100|0 */ {0x1ffffc8,25}, - /* (237) |11111111|11111111|11100100|1 */ {0x1ffffc9,25}, - /* (238) |11111111|11111111|11100101|0 */ {0x1ffffca,25}, - /* (239) |11111111|11111111|11100101|1 */ {0x1ffffcb,25}, - /* (240) |11111111|11111111|11100110|0 */ {0x1ffffcc,25}, - /* (241) |11111111|11111111|11100110|1 */ {0x1ffffcd,25}, - /* (242) |11111111|11111111|11100111|0 */ {0x1ffffce,25}, - /* (243) |11111111|11111111|11100111|1 */ {0x1ffffcf,25}, - /* (244) |11111111|11111111|11101000|0 */ {0x1ffffd0,25}, - /* (245) |11111111|11111111|11101000|1 */ {0x1ffffd1,25}, - /* (246) |11111111|11111111|11101001|0 */ {0x1ffffd2,25}, - /* (247) |11111111|11111111|11101001|1 */ {0x1ffffd3,25}, - /* (248) |11111111|11111111|11101010|0 */ {0x1ffffd4,25}, - /* (249) |11111111|11111111|11101010|1 */ {0x1ffffd5,25}, - /* (250) |11111111|11111111|11101011|0 */ {0x1ffffd6,25}, - /* (251) |11111111|11111111|11101011|1 */ {0x1ffffd7,25}, - /* (252) |11111111|11111111|11101100|0 */ {0x1ffffd8,25}, - /* (253) |11111111|11111111|11101100|1 */ {0x1ffffd9,25}, - /* (254) |11111111|11111111|11101101|0 */ {0x1ffffda,25}, - /* (255) |11111111|11111111|11101101|1 */ {0x1ffffdb,25}, - /*EOS (256) |11111111|11111111|11101110|0 */ {0x1ffffdc,25}, - + /* ( 0) |11111111|11000 */ {0x1ff8,13}, + /* ( 1) |11111111|11111111|1011000 */ {0x7fffd8,23}, + /* ( 2) |11111111|11111111|11111110|0010 */ {0xfffffe2,28}, + /* ( 3) |11111111|11111111|11111110|0011 */ {0xfffffe3,28}, + /* ( 4) |11111111|11111111|11111110|0100 */ {0xfffffe4,28}, + /* ( 5) |11111111|11111111|11111110|0101 */ {0xfffffe5,28}, + /* ( 6) |11111111|11111111|11111110|0110 */ {0xfffffe6,28}, + /* ( 7) |11111111|11111111|11111110|0111 */ {0xfffffe7,28}, + /* ( 8) |11111111|11111111|11111110|1000 */ {0xfffffe8,28}, + /* ( 9) |11111111|11111111|11101010 */ {0xffffea,24}, + /* ( 10) |11111111|11111111|11111111|111100 */ {0x3ffffffc,30}, + /* ( 11) |11111111|11111111|11111110|1001 */ {0xfffffe9,28}, + /* ( 12) |11111111|11111111|11111110|1010 */ {0xfffffea,28}, + /* ( 13) |11111111|11111111|11111111|111101 */ {0x3ffffffd,30}, + /* ( 14) |11111111|11111111|11111110|1011 */ {0xfffffeb,28}, + /* ( 15) |11111111|11111111|11111110|1100 */ {0xfffffec,28}, + /* ( 16) |11111111|11111111|11111110|1101 */ {0xfffffed,28}, + /* ( 17) |11111111|11111111|11111110|1110 */ {0xfffffee,28}, + /* ( 18) |11111111|11111111|11111110|1111 */ {0xfffffef,28}, + /* ( 19) |11111111|11111111|11111111|0000 */ {0xffffff0,28}, + /* ( 20) |11111111|11111111|11111111|0001 */ {0xffffff1,28}, + /* ( 21) |11111111|11111111|11111111|0010 */ {0xffffff2,28}, + /* ( 22) |11111111|11111111|11111111|111110 */ {0x3ffffffe,30}, + /* ( 23) |11111111|11111111|11111111|0011 */ {0xffffff3,28}, + /* ( 24) |11111111|11111111|11111111|0100 */ {0xffffff4,28}, + /* ( 25) |11111111|11111111|11111111|0101 */ {0xffffff5,28}, + /* ( 26) |11111111|11111111|11111111|0110 */ {0xffffff6,28}, + /* ( 27) |11111111|11111111|11111111|0111 */ {0xffffff7,28}, + /* ( 28) |11111111|11111111|11111111|1000 */ {0xffffff8,28}, + /* ( 29) |11111111|11111111|11111111|1001 */ {0xffffff9,28}, + /* ( 30) |11111111|11111111|11111111|1010 */ {0xffffffa,28}, + /* ( 31) |11111111|11111111|11111111|1011 */ {0xffffffb,28}, + /*' ' ( 32) |010100 */ {0x14, 6}, + /*'!' ( 33) |11111110|00 */ {0x3f8,10}, + /*'"' ( 34) |11111110|01 */ {0x3f9,10}, + /*'#' ( 35) |11111111|1010 */ {0xffa,12}, + /*'$' ( 36) |11111111|11001 */ {0x1ff9,13}, + /*'%' ( 37) |010101 */ {0x15, 6}, + /*'&' ( 38) |11111000 */ {0xf8, 8}, + /*''' ( 39) |11111111|010 */ {0x7fa,11}, + /*'(' ( 40) |11111110|10 */ {0x3fa,10}, + /*')' ( 41) |11111110|11 */ {0x3fb,10}, + /*'*' ( 42) |11111001 */ {0xf9, 8}, + /*'+' ( 43) |11111111|011 */ {0x7fb,11}, + /*',' ( 44) |11111010 */ {0xfa, 8}, + /*'-' ( 45) |010110 */ {0x16, 6}, + /*'.' ( 46) |010111 */ {0x17, 6}, + /*'/' ( 47) |011000 */ {0x18, 6}, + /*'0' ( 48) |00000 */ {0x0, 5}, + /*'1' ( 49) |00001 */ {0x1, 5}, + /*'2' ( 50) |00010 */ {0x2, 5}, + /*'3' ( 51) |011001 */ {0x19, 6}, + /*'4' ( 52) |011010 */ {0x1a, 6}, + /*'5' ( 53) |011011 */ {0x1b, 6}, + /*'6' ( 54) |011100 */ {0x1c, 6}, + /*'7' ( 55) |011101 */ {0x1d, 6}, + /*'8' ( 56) |011110 */ {0x1e, 6}, + /*'9' ( 57) |011111 */ {0x1f, 6}, + /*':' ( 58) |1011100 */ {0x5c, 7}, + /*';' ( 59) |11111011 */ {0xfb, 8}, + /*'<' ( 60) |11111111|1111100 */ {0x7ffc,15}, + /*'=' ( 61) |100000 */ {0x20, 6}, + /*'>' ( 62) |11111111|1011 */ {0xffb,12}, + /*'?' ( 63) |11111111|00 */ {0x3fc,10}, + /*'@' ( 64) |11111111|11010 */ {0x1ffa,13}, + /*'A' ( 65) |100001 */ {0x21, 6}, + /*'B' ( 66) |1011101 */ {0x5d, 7}, + /*'C' ( 67) |1011110 */ {0x5e, 7}, + /*'D' ( 68) |1011111 */ {0x5f, 7}, + /*'E' ( 69) |1100000 */ {0x60, 7}, + /*'F' ( 70) |1100001 */ {0x61, 7}, + /*'G' ( 71) |1100010 */ {0x62, 7}, + /*'H' ( 72) |1100011 */ {0x63, 7}, + /*'I' ( 73) |1100100 */ {0x64, 7}, + /*'J' ( 74) |1100101 */ {0x65, 7}, + /*'K' ( 75) |1100110 */ {0x66, 7}, + /*'L' ( 76) |1100111 */ {0x67, 7}, + /*'M' ( 77) |1101000 */ {0x68, 7}, + /*'N' ( 78) |1101001 */ {0x69, 7}, + /*'O' ( 79) |1101010 */ {0x6a, 7}, + /*'P' ( 80) |1101011 */ {0x6b, 7}, + /*'Q' ( 81) |1101100 */ {0x6c, 7}, + /*'R' ( 82) |1101101 */ {0x6d, 7}, + /*'S' ( 83) |1101110 */ {0x6e, 7}, + /*'T' ( 84) |1101111 */ {0x6f, 7}, + /*'U' ( 85) |1110000 */ {0x70, 7}, + /*'V' ( 86) |1110001 */ {0x71, 7}, + /*'W' ( 87) |1110010 */ {0x72, 7}, + /*'X' ( 88) |11111100 */ {0xfc, 8}, + /*'Y' ( 89) |1110011 */ {0x73, 7}, + /*'Z' ( 90) |11111101 */ {0xfd, 8}, + /*'[' ( 91) |11111111|11011 */ {0x1ffb,13}, + /*'\' ( 92) |11111111|11111110|000 */ {0x7fff0,19}, + /*']' ( 93) |11111111|11100 */ {0x1ffc,13}, + /*'^' ( 94) |11111111|111100 */ {0x3ffc,14}, + /*'_' ( 95) |100010 */ {0x22, 6}, + /*'`' ( 96) |11111111|1111101 */ {0x7ffd,15}, + /*'a' ( 97) |00011 */ {0x3, 5}, + /*'b' ( 98) |100011 */ {0x23, 6}, + /*'c' ( 99) |00100 */ {0x4, 5}, + /*'d' (100) |100100 */ {0x24, 6}, + /*'e' (101) |00101 */ {0x5, 5}, + /*'f' (102) |100101 */ {0x25, 6}, + /*'g' (103) |100110 */ {0x26, 6}, + /*'h' (104) |100111 */ {0x27, 6}, + /*'i' (105) |00110 */ {0x6, 5}, + /*'j' (106) |1110100 */ {0x74, 7}, + /*'k' (107) |1110101 */ {0x75, 7}, + /*'l' (108) |101000 */ {0x28, 6}, + /*'m' (109) |101001 */ {0x29, 6}, + /*'n' (110) |101010 */ {0x2a, 6}, + /*'o' (111) |00111 */ {0x7, 5}, + /*'p' (112) |101011 */ {0x2b, 6}, + /*'q' (113) |1110110 */ {0x76, 7}, + /*'r' (114) |101100 */ {0x2c, 6}, + /*'s' (115) |01000 */ {0x8, 5}, + /*'t' (116) |01001 */ {0x9, 5}, + /*'u' (117) |101101 */ {0x2d, 6}, + /*'v' (118) |1110111 */ {0x77, 7}, + /*'w' (119) |1111000 */ {0x78, 7}, + /*'x' (120) |1111001 */ {0x79, 7}, + /*'y' (121) |1111010 */ {0x7a, 7}, + /*'z' (122) |1111011 */ {0x7b, 7}, + /*'{' (123) |11111111|1111110 */ {0x7ffe,15}, + /*'|' (124) |11111111|100 */ {0x7fc,11}, + /*'}' (125) |11111111|111101 */ {0x3ffd,14}, + /*'~' (126) |11111111|11101 */ {0x1ffd,13}, + /* (127) |11111111|11111111|11111111|1100 */ {0xffffffc,28}, + /* (128) |11111111|11111110|0110 */ {0xfffe6,20}, + /* (129) |11111111|11111111|010010 */ {0x3fffd2,22}, + /* (130) |11111111|11111110|0111 */ {0xfffe7,20}, + /* (131) |11111111|11111110|1000 */ {0xfffe8,20}, + /* (132) |11111111|11111111|010011 */ {0x3fffd3,22}, + /* (133) |11111111|11111111|010100 */ {0x3fffd4,22}, + /* (134) |11111111|11111111|010101 */ {0x3fffd5,22}, + /* (135) |11111111|11111111|1011001 */ {0x7fffd9,23}, + /* (136) |11111111|11111111|010110 */ {0x3fffd6,22}, + /* (137) |11111111|11111111|1011010 */ {0x7fffda,23}, + /* (138) |11111111|11111111|1011011 */ {0x7fffdb,23}, + /* (139) |11111111|11111111|1011100 */ {0x7fffdc,23}, + /* (140) |11111111|11111111|1011101 */ {0x7fffdd,23}, + /* (141) |11111111|11111111|1011110 */ {0x7fffde,23}, + /* (142) |11111111|11111111|11101011 */ {0xffffeb,24}, + /* (143) |11111111|11111111|1011111 */ {0x7fffdf,23}, + /* (144) |11111111|11111111|11101100 */ {0xffffec,24}, + /* (145) |11111111|11111111|11101101 */ {0xffffed,24}, + /* (146) |11111111|11111111|010111 */ {0x3fffd7,22}, + /* (147) |11111111|11111111|1100000 */ {0x7fffe0,23}, + /* (148) |11111111|11111111|11101110 */ {0xffffee,24}, + /* (149) |11111111|11111111|1100001 */ {0x7fffe1,23}, + /* (150) |11111111|11111111|1100010 */ {0x7fffe2,23}, + /* (151) |11111111|11111111|1100011 */ {0x7fffe3,23}, + /* (152) |11111111|11111111|1100100 */ {0x7fffe4,23}, + /* (153) |11111111|11111110|11100 */ {0x1fffdc,21}, + /* (154) |11111111|11111111|011000 */ {0x3fffd8,22}, + /* (155) |11111111|11111111|1100101 */ {0x7fffe5,23}, + /* (156) |11111111|11111111|011001 */ {0x3fffd9,22}, + /* (157) |11111111|11111111|1100110 */ {0x7fffe6,23}, + /* (158) |11111111|11111111|1100111 */ {0x7fffe7,23}, + /* (159) |11111111|11111111|11101111 */ {0xffffef,24}, + /* (160) |11111111|11111111|011010 */ {0x3fffda,22}, + /* (161) |11111111|11111110|11101 */ {0x1fffdd,21}, + /* (162) |11111111|11111110|1001 */ {0xfffe9,20}, + /* (163) |11111111|11111111|011011 */ {0x3fffdb,22}, + /* (164) |11111111|11111111|011100 */ {0x3fffdc,22}, + /* (165) |11111111|11111111|1101000 */ {0x7fffe8,23}, + /* (166) |11111111|11111111|1101001 */ {0x7fffe9,23}, + /* (167) |11111111|11111110|11110 */ {0x1fffde,21}, + /* (168) |11111111|11111111|1101010 */ {0x7fffea,23}, + /* (169) |11111111|11111111|011101 */ {0x3fffdd,22}, + /* (170) |11111111|11111111|011110 */ {0x3fffde,22}, + /* (171) |11111111|11111111|11110000 */ {0xfffff0,24}, + /* (172) |11111111|11111110|11111 */ {0x1fffdf,21}, + /* (173) |11111111|11111111|011111 */ {0x3fffdf,22}, + /* (174) |11111111|11111111|1101011 */ {0x7fffeb,23}, + /* (175) |11111111|11111111|1101100 */ {0x7fffec,23}, + /* (176) |11111111|11111111|00000 */ {0x1fffe0,21}, + /* (177) |11111111|11111111|00001 */ {0x1fffe1,21}, + /* (178) |11111111|11111111|100000 */ {0x3fffe0,22}, + /* (179) |11111111|11111111|00010 */ {0x1fffe2,21}, + /* (180) |11111111|11111111|1101101 */ {0x7fffed,23}, + /* (181) |11111111|11111111|100001 */ {0x3fffe1,22}, + /* (182) |11111111|11111111|1101110 */ {0x7fffee,23}, + /* (183) |11111111|11111111|1101111 */ {0x7fffef,23}, + /* (184) |11111111|11111110|1010 */ {0xfffea,20}, + /* (185) |11111111|11111111|100010 */ {0x3fffe2,22}, + /* (186) |11111111|11111111|100011 */ {0x3fffe3,22}, + /* (187) |11111111|11111111|100100 */ {0x3fffe4,22}, + /* (188) |11111111|11111111|1110000 */ {0x7ffff0,23}, + /* (189) |11111111|11111111|100101 */ {0x3fffe5,22}, + /* (190) |11111111|11111111|100110 */ {0x3fffe6,22}, + /* (191) |11111111|11111111|1110001 */ {0x7ffff1,23}, + /* (192) |11111111|11111111|11111000|00 */ {0x3ffffe0,26}, + /* (193) |11111111|11111111|11111000|01 */ {0x3ffffe1,26}, + /* (194) |11111111|11111110|1011 */ {0xfffeb,20}, + /* (195) |11111111|11111110|001 */ {0x7fff1,19}, + /* (196) |11111111|11111111|100111 */ {0x3fffe7,22}, + /* (197) |11111111|11111111|1110010 */ {0x7ffff2,23}, + /* (198) |11111111|11111111|101000 */ {0x3fffe8,22}, + /* (199) |11111111|11111111|11110110|0 */ {0x1ffffec,25}, + /* (200) |11111111|11111111|11111000|10 */ {0x3ffffe2,26}, + /* (201) |11111111|11111111|11111000|11 */ {0x3ffffe3,26}, + /* (202) |11111111|11111111|11111001|00 */ {0x3ffffe4,26}, + /* (203) |11111111|11111111|11111011|110 */ {0x7ffffde,27}, + /* (204) |11111111|11111111|11111011|111 */ {0x7ffffdf,27}, + /* (205) |11111111|11111111|11111001|01 */ {0x3ffffe5,26}, + /* (206) |11111111|11111111|11110001 */ {0xfffff1,24}, + /* (207) |11111111|11111111|11110110|1 */ {0x1ffffed,25}, + /* (208) |11111111|11111110|010 */ {0x7fff2,19}, + /* (209) |11111111|11111111|00011 */ {0x1fffe3,21}, + /* (210) |11111111|11111111|11111001|10 */ {0x3ffffe6,26}, + /* (211) |11111111|11111111|11111100|000 */ {0x7ffffe0,27}, + /* (212) |11111111|11111111|11111100|001 */ {0x7ffffe1,27}, + /* (213) |11111111|11111111|11111001|11 */ {0x3ffffe7,26}, + /* (214) |11111111|11111111|11111100|010 */ {0x7ffffe2,27}, + /* (215) |11111111|11111111|11110010 */ {0xfffff2,24}, + /* (216) |11111111|11111111|00100 */ {0x1fffe4,21}, + /* (217) |11111111|11111111|00101 */ {0x1fffe5,21}, + /* (218) |11111111|11111111|11111010|00 */ {0x3ffffe8,26}, + /* (219) |11111111|11111111|11111010|01 */ {0x3ffffe9,26}, + /* (220) |11111111|11111111|11111111|1101 */ {0xffffffd,28}, + /* (221) |11111111|11111111|11111100|011 */ {0x7ffffe3,27}, + /* (222) |11111111|11111111|11111100|100 */ {0x7ffffe4,27}, + /* (223) |11111111|11111111|11111100|101 */ {0x7ffffe5,27}, + /* (224) |11111111|11111110|1100 */ {0xfffec,20}, + /* (225) |11111111|11111111|11110011 */ {0xfffff3,24}, + /* (226) |11111111|11111110|1101 */ {0xfffed,20}, + /* (227) |11111111|11111111|00110 */ {0x1fffe6,21}, + /* (228) |11111111|11111111|101001 */ {0x3fffe9,22}, + /* (229) |11111111|11111111|00111 */ {0x1fffe7,21}, + /* (230) |11111111|11111111|01000 */ {0x1fffe8,21}, + /* (231) |11111111|11111111|1110011 */ {0x7ffff3,23}, + /* (232) |11111111|11111111|101010 */ {0x3fffea,22}, + /* (233) |11111111|11111111|101011 */ {0x3fffeb,22}, + /* (234) |11111111|11111111|11110111|0 */ {0x1ffffee,25}, + /* (235) |11111111|11111111|11110111|1 */ {0x1ffffef,25}, + /* (236) |11111111|11111111|11110100 */ {0xfffff4,24}, + /* (237) |11111111|11111111|11110101 */ {0xfffff5,24}, + /* (238) |11111111|11111111|11111010|10 */ {0x3ffffea,26}, + /* (239) |11111111|11111111|1110100 */ {0x7ffff4,23}, + /* (240) |11111111|11111111|11111010|11 */ {0x3ffffeb,26}, + /* (241) |11111111|11111111|11111100|110 */ {0x7ffffe6,27}, + /* (242) |11111111|11111111|11111011|00 */ {0x3ffffec,26}, + /* (243) |11111111|11111111|11111011|01 */ {0x3ffffed,26}, + /* (244) |11111111|11111111|11111100|111 */ {0x7ffffe7,27}, + /* (245) |11111111|11111111|11111101|000 */ {0x7ffffe8,27}, + /* (246) |11111111|11111111|11111101|001 */ {0x7ffffe9,27}, + /* (247) |11111111|11111111|11111101|010 */ {0x7ffffea,27}, + /* (248) |11111111|11111111|11111101|011 */ {0x7ffffeb,27}, + /* (249) |11111111|11111111|11111111|1110 */ {0xffffffe,28}, + /* (250) |11111111|11111111|11111101|100 */ {0x7ffffec,27}, + /* (251) |11111111|11111111|11111101|101 */ {0x7ffffed,27}, + /* (252) |11111111|11111111|11111101|110 */ {0x7ffffee,27}, + /* (253) |11111111|11111111|11111101|111 */ {0x7ffffef,27}, + /* (254) |11111111|11111111|11111110|000 */ {0x7fffff0,27}, + /* (255) |11111111|11111111|11111011|10 */ {0x3ffffee,26}, + /*EOS (256) |11111111|11111111|11111111|111111 */ {0x3fffffff,30}, }; static final int[][] LCCODES = new int[CODES.length][]; diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index 397a36d82a7..fbbc1b5c953 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -92,13 +92,12 @@ public class HpackDecoderTest } @Test - @Ignore public void testDecodeD_4() { HpackDecoder decoder = new HpackDecoder(4096,8192); // First request - String encoded="828786448ce7cf9bebe89b6fb16fa9b6ff"; + String encoded="828684418cf1e3c2e5f23a6ba0ab90f4ff"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); @@ -108,10 +107,9 @@ public class HpackDecoderTest assertEquals("/",request.getURI().getPath()); assertEquals("www.example.com",request.getURI().getHost()); assertFalse(request.iterator().hasNext()); - - + // Second request - encoded="5c86b9b9949556bf"; + encoded="828684be5886a8eb10649cbf"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); @@ -125,20 +123,6 @@ public class HpackDecoderTest assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); assertFalse(iterator.hasNext()); - // Third request - encoded="30858c8b844088571c5cdb737b2faf89571c5cdb73724d9c57"; - buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - - request = (MetaData.Request)decoder.decode(buffer); - - assertEquals("GET",request.getMethod()); - assertEquals(HttpScheme.HTTPS.asString(),request.getURI().getScheme()); - assertEquals("/index.html",request.getURI().getPath()); - assertEquals("www.example.com",request.getURI().getHost()); - iterator=request.iterator(); - assertTrue(iterator.hasNext()); - assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); - assertFalse(iterator.hasNext()); } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java index c7bffc8b688..f927ebfe9a2 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java @@ -25,9 +25,9 @@ import java.io.FilenameFilter; import java.nio.ByteBuffer; import java.util.Map; -import org.eclipse.jetty.http.FinalMetaData; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.ajax.JSON; @@ -121,7 +121,7 @@ public class HpackPerfTest } BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new FinalMetaData(HttpVersion.HTTP_2,fields)); + encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); _encodedSize+=buffer.remaining(); diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java index a0acecf3158..134df0b3c88 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java @@ -29,15 +29,13 @@ public class HuffmanTest { String[][] tests = { - {"D.4.1","e7cf9bebe89b6fb16fa9b6ff","www.example.com"}, - {"D.4.2","b9b9949556bf","no-cache"}, - {"D.4.3k","571c5cdb737b2faf","custom-key"}, - {"D.4.3v","571c5cdb73724d9c57","custom-value"}, - {"D.6.1d","d6dbb29884de2a718805062098513109b56ba3","Mon, 21 Oct 2013 20:13:21 GMT"}, - {"D.6.1l","adcebf198e7e7cf9bebe89b6fb16fa9b6f","https://www.example.com"}, - {"D.6.2te","abdd97ff","gzip"}, - {"D.4.2cookie","e0d6cf9f6e8f9fd3e5f6fa76fefd3c7edf9eff1f2f0f3cfe9f6fcf7f8f879f61ad4f4cc9a973a2200ec3725e18b1b74e3f","foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"}, - {"D.6.2date","d6dbb29884de2a718805062098513111b56ba3","Mon, 21 Oct 2013 20:13:22 GMT"}, + {"D.4.1","f1e3c2e5f23a6ba0ab90f4ff","www.example.com"}, + {"D.4.2","a8eb10649cbf","no-cache"}, + {"D.6.1k","6402","302"}, + {"D.6.1v","aec3771a4b","private"}, + {"D.6.1d","d07abe941054d444a8200595040b8166e082a62d1bff","Mon, 21 Oct 2013 20:13:21 GMT"}, + {"D.6.1l","9d29ad171863c78f0b97c8e9ae82ae43d3","https://www.example.com"}, + {"D.6.2te","640cff","303"}, }; @Test diff --git a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties index d33a7c32778..e40e8e43ce1 100644 --- a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties @@ -1,3 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog org.eclipse.jetty.http2.LEVEL=INFO -org.eclipse.jetty.http2.hpack.LEVEL=DEBUG +org.eclipse.jetty.http2.hpack.LEVEL=INFO From 8905b979ec3ed1ccd1a02374e44bb50b5aa36767 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Mon, 28 Jul 2014 15:27:17 +1000 Subject: [PATCH 156/269] RFC7238 Permanent Redirect 308 defined --- .../org/eclipse/jetty/http/HttpStatus.java | 131 ++++++++++-------- 1 file changed, 73 insertions(+), 58 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java index 7db1fa64ff0..881acbd679b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java @@ -29,10 +29,12 @@ package org.eclipse.jetty.http; * <th>Enum</th> * <th>Code</th> * <th>Message</th> - * <th> + * <th> * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a></th> + * <th> + * <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1 Semantics and Content</a></th> * <th> - * <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a></th> + * <a href="http://tools.ietf.org/html/rfc7238">RFC 7238 - HTTP/1.1 Permanent Redirect</a></th> * <th> * <a href="http://tools.ietf.org/html/rfc2518">RFC 2518 - WEBDAV</a></th> * </tr> @@ -48,7 +50,7 @@ package org.eclipse.jetty.http; * <td>Continue</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.1.1">Sec. 10.1.1</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.2.1">Sec. 6.2.1</a></td> * <td> </td> * </tr> * <tr> @@ -57,7 +59,7 @@ package org.eclipse.jetty.http; * <td>Switching Protocols</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.1.2">Sec. 10.1.2</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.2.2">Sec. 6.2.2</a></td> * <td> </td> * </tr> * <tr> @@ -82,7 +84,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.2">Sec. 9.2</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.1">Sec. 10.2.1</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.1">Sec. 6.3.1</a></td> * <td> </td> * </tr> * <tr> @@ -92,7 +94,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.2">Sec. 9.2</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.2">Sec. 10.2.2</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.2">Sec. 6.3.2</a></td> * <td> </td> * </tr> * <tr> @@ -102,7 +104,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.2">Sec. 9.2</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.3">Sec. 10.2.3</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.3">Sec. 6.3.3</a></td> * <td> </td> * </tr> * <tr> @@ -111,7 +113,7 @@ package org.eclipse.jetty.http; * <td>Non Authoritative Information</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.4">Sec. 10.2.4</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.4">Sec. 6.3.4</a></td> * <td> </td> * </tr> * <tr> @@ -121,7 +123,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.2">Sec. 9.2</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.5">Sec. 10.2.5</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.5">Sec. 6.3.5</a></td> * <td> </td> * </tr> * <tr> @@ -130,7 +132,7 @@ package org.eclipse.jetty.http; * <td>Reset Content</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.6">Sec. 10.2.6</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.6">Sec. 6.3.6</a></td> * <td> </td> * </tr> * <tr> @@ -139,7 +141,7 @@ package org.eclipse.jetty.http; * <td>Partial Content</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.7">Sec. 10.2.7</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.7">Sec. 6.3.7</a></td> * <td> </td> * </tr> * <tr> @@ -175,7 +177,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.3">Sec. 9.3</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.1">Sec. 10.3.1</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.1">Sec. 6.4.1</a></td> * <td> </td> * </tr> * <tr> @@ -185,7 +187,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.3">Sec. 9.3</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.2">Sec. 10.3.2</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.2">Sec. 6.4.2</a></td> * <td> </td> * </tr> * <tr> @@ -203,7 +205,7 @@ package org.eclipse.jetty.http; * <td>Found</td> * <td>(was "<code>302 Moved Temporarily</code>")</td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.3">Sec. 10.3.3</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.3">Sec. 6.4.3</a></td> * <td> </td> * </tr> * <tr> @@ -212,7 +214,7 @@ package org.eclipse.jetty.http; * <td>See Other</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.4">Sec. 10.3.4</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.4">Sec. 6.4.4</a></td> * <td> </td> * </tr> * <tr> @@ -222,7 +224,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.3">Sec. 9.3</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.5">Sec. 10.3.5</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.5">Sec. 6.4.5</a></td> * <td> </td> * </tr> * <tr> @@ -231,7 +233,7 @@ package org.eclipse.jetty.http; * <td>Use Proxy</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.6">Sec. 10.3.6</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.6">Sec. 6.4.6</a></td> * <td> </td> * </tr> * <tr> @@ -240,7 +242,7 @@ package org.eclipse.jetty.http; * <td><em>(Unused)</em></td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.7">Sec. 10.3.7</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.7">Sec. 6.4.7</a></td> * <td> </td> * </tr> * <tr> @@ -249,7 +251,17 @@ package org.eclipse.jetty.http; * <td>Temporary Redirect</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.8">Sec. 10.3.8</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.8">Sec. 6.4.8</a></td> + * <td> </td> + * </tr> + * + * <tr> + * <td>{@link #PERMANENT_REDIRECT_308}</td> + * <td>307</td> + * <td>Permanent Redirect</td> + * <td> </td> + * <td> + * <a href="http://tools.ietf.org/html/rfc7238">RFC7238</a></td> * <td> </td> * </tr> * @@ -265,7 +277,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.1">Sec. 10.4.1</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.1">Sec. 6.5.1</a></td> * <td> </td> * </tr> * <tr> @@ -275,7 +287,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.2">Sec. 10.4.2</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.2">Sec. 6.5.2</a></td> * <td> </td> * </tr> * <tr> @@ -285,7 +297,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.3">Sec. 10.4.3</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.3">Sec. 6.5.3</a></td> * <td> </td> * </tr> * <tr> @@ -295,7 +307,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.4">Sec. 10.4.4</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.4">Sec. 6.5.4</a></td> * <td> </td> * </tr> * <tr> @@ -305,7 +317,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.5">Sec. 10.4.5</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.5">Sec. 6.5.5</a></td> * <td> </td> * </tr> * <tr> @@ -314,7 +326,7 @@ package org.eclipse.jetty.http; * <td>Method Not Allowed</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.6">Sec. 10.4.6</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.6">Sec. 6.5.6</a></td> * <td> </td> * </tr> * <tr> @@ -323,7 +335,7 @@ package org.eclipse.jetty.http; * <td>Not Acceptable</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.7">Sec. 10.4.7</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.7">Sec. 6.5.7</a></td> * <td> </td> * </tr> * <tr> @@ -332,7 +344,7 @@ package org.eclipse.jetty.http; * <td>Proxy Authentication Required</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.8">Sec. 10.4.8</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.8">Sec. 6.5.8</a></td> * <td> </td> * </tr> * <tr> @@ -341,7 +353,7 @@ package org.eclipse.jetty.http; * <td>Request Timeout</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.9">Sec. 10.4.9</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.9">Sec. 6.5.9</a></td> * <td> </td> * </tr> * <tr> @@ -350,7 +362,7 @@ package org.eclipse.jetty.http; * <td>Conflict</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.10">Sec. 10.4.10</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.10">Sec. 10.4.10</a> * </td> * <td> </td> * </tr> @@ -360,7 +372,7 @@ package org.eclipse.jetty.http; * <td>Gone</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.11">Sec. 10.4.11</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.11">Sec. 10.4.11</a> * </td> * <td> </td> * </tr> @@ -370,7 +382,7 @@ package org.eclipse.jetty.http; * <td>Length Required</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.12">Sec. 10.4.12</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.12">Sec. 10.4.12</a> * </td> * <td> </td> * </tr> @@ -380,7 +392,7 @@ package org.eclipse.jetty.http; * <td>Precondition Failed</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.13">Sec. 10.4.13</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.13">Sec. 10.4.13</a> * </td> * <td> </td> * </tr> @@ -390,7 +402,7 @@ package org.eclipse.jetty.http; * <td>Request Entity Too Large</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.14">Sec. 10.4.14</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.14">Sec. 10.4.14</a> * </td> * <td> </td> * </tr> @@ -400,7 +412,7 @@ package org.eclipse.jetty.http; * <td>Request-URI Too Long</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.15">Sec. 10.4.15</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.15">Sec. 10.4.15</a> * </td> * <td> </td> * </tr> @@ -410,7 +422,7 @@ package org.eclipse.jetty.http; * <td>Unsupported Media Type</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.16">Sec. 10.4.16</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.16">Sec. 10.4.16</a> * </td> * <td> </td> * </tr> @@ -420,7 +432,7 @@ package org.eclipse.jetty.http; * <td>Requested Range Not Satisfiable</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.17">Sec. 10.4.17</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.17">Sec. 10.4.17</a> * </td> * <td> </td> * </tr> @@ -430,7 +442,7 @@ package org.eclipse.jetty.http; * <td>Expectation Failed</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.18">Sec. 10.4.18</a> + * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.18">Sec. 10.4.18</a> * </td> * <td> </td> * </tr> @@ -537,7 +549,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.5">Sec. 9.5</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.1">Sec. 10.5.1</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.1">Sec. 6.6.1</a></td> * <td> </td> * </tr> * <tr> @@ -547,7 +559,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.5">Sec. 9.5</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.2">Sec. 10.5.2</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.2">Sec. 6.6.2</a></td> * <td> </td> * </tr> * <tr> @@ -557,7 +569,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.5">Sec. 9.5</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.3">Sec. 10.5.3</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.3">Sec. 6.6.3</a></td> * <td> </td> * </tr> * <tr> @@ -567,7 +579,7 @@ package org.eclipse.jetty.http; * <td> * <a href="http://tools.ietf.org/html/rfc1945#section-9.5">Sec. 9.5</a></td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.4">Sec. 10.5.4</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.4">Sec. 6.6.4</a></td> * <td> </td> * </tr> * <tr> @@ -576,7 +588,7 @@ package org.eclipse.jetty.http; * <td>Gateway Timeout</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.5">Sec. 10.5.5</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.5">Sec. 6.6.5</a></td> * <td> </td> * </tr> * <tr> @@ -585,7 +597,7 @@ package org.eclipse.jetty.http; * <td>HTTP Version Not Supported</td> * <td> </td> * <td> - * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.6">Sec. 10.5.6</a></td> + * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.6">Sec. 6.6.6</a></td> * <td> </td> * </tr> * <tr> @@ -633,6 +645,7 @@ public class HttpStatus public final static int NOT_MODIFIED_304 = 304; public final static int USE_PROXY_305 = 305; public final static int TEMPORARY_REDIRECT_307 = 307; + public final static int PERMANENT_REDIRECT_308 = 308; public final static int BAD_REQUEST_400 = 400; public final static int UNAUTHORIZED_401 = 401; @@ -683,7 +696,7 @@ public class HttpStatus /* * -------------------------------------------------------------------- * Informational messages in 1xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV + * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV */ /** <code>100 Continue</code> */ @@ -696,7 +709,7 @@ public class HttpStatus /* * -------------------------------------------------------------------- * Success messages in 2xx series. As defined by ... RFC 1945 - HTTP/1.0 - * RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV + * RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV */ /** <code>200 OK</code> */ @@ -719,7 +732,7 @@ public class HttpStatus /* * -------------------------------------------------------------------- * Redirection messages in 3xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 2616 - HTTP/1.1 + * HTTP/1.0 RFC 7231 - HTTP/1.1 */ /** <code>300 Mutliple Choices</code> */ @@ -738,11 +751,13 @@ public class HttpStatus USE_PROXY(USE_PROXY_305, "Use Proxy"), /** <code>307 Temporary Redirect</code> */ TEMPORARY_REDIRECT(TEMPORARY_REDIRECT_307, "Temporary Redirect"), + /** <code>308 Permanent Redirect</code> */ + PERMANET_REDIRECT(PERMANENT_REDIRECT_308, "Permanent Redirect"), /* * -------------------------------------------------------------------- * Client Error messages in 4xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV + * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV */ /** <code>400 Bad Request</code> */ @@ -791,7 +806,7 @@ public class HttpStatus /* * -------------------------------------------------------------------- * Server Error messages in 5xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV + * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV */ /** <code>500 Server Error</code> */ @@ -844,7 +859,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Informational</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, - * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - + * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - * HTTP/1.1</a>. * * @return true if within range of codes that belongs to @@ -859,7 +874,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Success</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, - * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - + * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - * HTTP/1.1</a>. * * @return true if within range of codes that belongs to @@ -874,7 +889,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Redirection</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, - * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - + * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - * HTTP/1.1</a>. * * @return true if within range of codes that belongs to @@ -889,7 +904,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Client Error</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, - * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - + * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - * HTTP/1.1</a>. * * @return true if within range of codes that belongs to @@ -904,7 +919,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Server Error</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, - * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - + * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - * HTTP/1.1</a>. * * @return true if within range of codes that belongs to @@ -958,7 +973,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Informational</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a - * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>. * * @param code * the code to test. @@ -974,7 +989,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Success</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a - * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>. * * @param code * the code to test. @@ -990,7 +1005,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Redirection</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a - * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>. * * @param code * the code to test. @@ -1006,7 +1021,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Client Error</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a - * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>. * * @param code * the code to test. @@ -1022,7 +1037,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * <code>Server Error</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a - * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>. * * @param code * the code to test. From 5d8780cb4e55ad3d6064d25de26e9aa29caf919d Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Mon, 28 Jul 2014 15:27:40 +1000 Subject: [PATCH 157/269] Record some TODOs --- .../jetty/http2/server/HTTP2ServerConnectionFactory.java | 2 ++ .../org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java | 2 +- .../src/main/java/org/eclipse/jetty/server/Request.java | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 29abe5fe40a..22a44885926 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -95,6 +95,8 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2((IStream)stream, frame); HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); + + // TODO pool HttpChannels per connection - maybe associate with thread? HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input, stream); stream.setAttribute(CHANNEL_ATTRIBUTE, channel); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 900736f7f38..2e0f6122c01 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -45,7 +45,7 @@ public class HttpChannelOverHTTP2 extends HttpChannel private static final HttpField ACCEPT_ENCODING_GZIP = new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip"); private static final HttpField SERVER_VERSION=new HttpField(HttpHeader.SERVER,HttpConfiguration.SERVER_VERSION); private static final HttpField POWERED_BY=new HttpField(HttpHeader.X_POWERED_BY,HttpConfiguration.SERVER_VERSION); - private final Stream stream; + private final Stream stream; // TODO recycle channel for new Stream? public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input, Stream stream) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 43bc0f2dc1e..4b1c23d4929 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -149,7 +149,7 @@ public class Request implements HttpServletRequest private boolean _handled = false; private boolean _paramsExtracted; private boolean _requestedSessionIdFromCookie = false; - private volatile Attributes _attributes; + private Attributes _attributes; private Authentication _authentication; private String _characterEncoding; private ContextHandler.Context _context; From 489830a0b20f9e34c04d451378990d56a2434d7a Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 30 Jul 2014 18:08:54 +1000 Subject: [PATCH 158/269] Prototype execution strategy --- .../jetty/util/thread/ExecutionStrategy.java | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java new file mode 100644 index 00000000000..994b1db8205 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java @@ -0,0 +1,169 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.util.thread; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + + +/* ------------------------------------------------------------ */ +/** Strategies to execute Producers + */ +public abstract class ExecutionStrategy implements Runnable +{ + public interface Producer + { + /** + * Produce a task to run + * @return A task to run or null if we are complete. + */ + Runnable produce(); + + /** + * Check if there is more to produce. This method may not return valid + * results until {@link #produce()} has been called. + * @return true if this Producer may produce more tasks from {@link #produce()} + */ + boolean isMoreToProduce(); + + /** + * Called to signal production is completed + */ + void onCompleted(); + } + + protected final Producer _producer; + protected final Executor _executor; + + protected ExecutionStrategy(Producer producer, Executor executor) + { + _producer=producer; + _executor=executor; + } + + + /* ------------------------------------------------------------ */ + /** Simple iterative strategy. + * Iterate over production until complete and execute each task. + */ + public static class Iterative extends ExecutionStrategy + { + public Iterative(Producer producer, Executor executor) + { + super(producer,executor); + } + + public void run() + { + try + { + // Iterate until we are complete + loop: while (true) + { + // produce a task + Runnable task=_producer.produce(); + + // if there is no task, break the loop + if (task==null) + break loop; + + // If we are still producing, + if (_producer.isMoreToProduce()) + // execute the task + _executor.execute(task); + else + { + // last task so we can run ourselves + task.run(); + break loop; + } + } + } + finally + { + _producer.onCompleted(); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * A Strategy that allows threads to run the tasks that they have produced, + * so execution is done with a hot cache (ie threads eat what they kill). + */ + public static class EatWhatYouKill extends ExecutionStrategy + { + private final AtomicInteger _threads = new AtomicInteger(0); + private final AtomicReference<Boolean> _producing = new AtomicReference<Boolean>(Boolean.FALSE); + + public EatWhatYouKill(Producer producer, Executor executor) + { + super(producer,executor); + } + + public void run() + { + // count the dispatched threads + _threads.incrementAndGet(); + try + { + boolean complete=false; + loop: while (!complete) + { + // If another thread is already producing, + if (!_producing.compareAndSet(false,true)) + // break the loop even if not complete + break loop; + + // If we got here, then we are the thread that is producing + Runnable task=null; + try + { + task=_producer.produce(); + complete=task==null || _producer.isMoreToProduce(); + } + finally + { + _producing.set(false); + } + + // then we may need another thread to keep producing + if (!complete) + // Dispatch a thread to continue producing + _executor.execute(this); + + // If there is a task, + if (task!=null) + // run the task + task.run(); + } + + } + finally + { + // If we were the last thread, signal completion + if (_threads.decrementAndGet()==0) + _producer.onCompleted(); + } + } + } + +} From e415de44c64775dd537bab59c89a913f132360b3 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 31 Jul 2014 08:58:19 +1000 Subject: [PATCH 159/269] Eat what you kill strategy avoids double dispatch --- .../org/eclipse/jetty/util/thread/ExecutionStrategy.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java index 994b1db8205..1159b93237b 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java @@ -59,7 +59,6 @@ public abstract class ExecutionStrategy implements Runnable _executor=executor; } - /* ------------------------------------------------------------ */ /** Simple iterative strategy. * Iterate over production until complete and execute each task. @@ -113,6 +112,7 @@ public abstract class ExecutionStrategy implements Runnable { private final AtomicInteger _threads = new AtomicInteger(0); private final AtomicReference<Boolean> _producing = new AtomicReference<Boolean>(Boolean.FALSE); + private volatile boolean _dispatched; public EatWhatYouKill(Producer producer, Executor executor) { @@ -121,6 +121,7 @@ public abstract class ExecutionStrategy implements Runnable public void run() { + _dispatched=false; // count the dispatched threads _threads.incrementAndGet(); try @@ -146,9 +147,12 @@ public abstract class ExecutionStrategy implements Runnable } // then we may need another thread to keep producing - if (!complete) + if (!complete && !_dispatched) + { // Dispatch a thread to continue producing + _dispatched=true; _executor.execute(this); + } // If there is a task, if (task!=null) From 70dafa8eb3ec0301b1c59301d752f5f5c977ced8 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 31 Jul 2014 11:53:51 +1000 Subject: [PATCH 160/269] simplified HttpTransport API --- .../fcgi/server/HttpTransportOverFCGI.java | 56 ++++++++++--------- .../http2/server/HttpTransportOverHTTP2.java | 6 +- .../org/eclipse/jetty/server/HttpChannel.java | 2 +- .../eclipse/jetty/server/HttpConnection.java | 7 --- .../eclipse/jetty/server/HttpTransport.java | 2 - .../eclipse/jetty/server/ResponseTest.java | 6 -- .../server/http/HttpTransportOverSPDY.java | 9 --- 7 files changed, 34 insertions(+), 54 deletions(-) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java index f1748337b72..54819e430ed 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java @@ -49,6 +49,36 @@ public class HttpTransportOverFCGI implements HttpTransport @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) + { + if (info!=null) + commit(info,content,lastContent,callback); + else + { + if (head) + { + if (lastContent) + { + Generator.Result result = generateResponseContent(BufferUtil.EMPTY_BUFFER, true, callback); + flusher.flush(result); + } + else + { + // Skip content generation + callback.succeeded(); + } + } + else + { + Generator.Result result = generateResponseContent(content, lastContent, callback); + flusher.flush(result); + } + + if (lastContent && shutdown) + flusher.shutdown(); + } + } + + private void commit(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { boolean head = this.head = info.isHead(); boolean shutdown = this.shutdown = info.getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); @@ -78,32 +108,6 @@ public class HttpTransportOverFCGI implements HttpTransport flusher.shutdown(); } - @Override - public void send(ByteBuffer content, boolean lastContent, Callback callback) - { - if (head) - { - if (lastContent) - { - Generator.Result result = generateResponseContent(BufferUtil.EMPTY_BUFFER, true, callback); - flusher.flush(result); - } - else - { - // Skip content generation - callback.succeeded(); - } - } - else - { - Generator.Result result = generateResponseContent(content, lastContent, callback); - flusher.flush(result); - } - - if (lastContent && shutdown) - flusher.shutdown(); - } - protected Generator.Result generateResponseHeaders(HttpGenerator.ResponseInfo info, Callback callback) { return generator.generateResponseHeaders(request, info.getStatus(), info.getReason(), info.getHttpFields(), callback); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index e9e8ad69b1e..55b9daa67e8 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -85,9 +85,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, endStream); stream.headers(frame, callback); } - - @Override - public void send(ByteBuffer content, boolean lastContent, Callback callback) + + private void send(ByteBuffer content, boolean lastContent, Callback callback) { if (LOG.isDebugEnabled()) { @@ -98,6 +97,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport stream.data(frame, callback); } + @Override public void completed() { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index a07d1032f3f..94e89d42c7c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -534,7 +534,7 @@ public class HttpChannel implements Runnable else if (info==null) { // This is a normal write - _transport.send(content, complete, callback); + _transport.send(null,content, complete, callback); } else { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index d020d582484..535ce6324a0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -443,13 +443,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _sendCallback.iterate(); } - @Override - public void send(ByteBuffer content, boolean lastContent, Callback callback) - { - _sendCallback.reset(null,content,lastContent,callback); - _sendCallback.iterate(); - } - private class SendCallback extends IteratingCallback { private ResponseInfo _info; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java index 7058425f659..d04a43e9bc3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java @@ -26,8 +26,6 @@ import org.eclipse.jetty.util.Callback; public interface HttpTransport { void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback); - - void send(ByteBuffer content, boolean lastContent, Callback callback); void completed(); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 15164a50c25..e68b6a0a4cc 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -90,12 +90,6 @@ public class ResponseTest { callback.succeeded(); } - - @Override - public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback) - { - send(null,responseBodyContent, lastContent, callback); - } @Override public void completed() diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java index 520ad181cdd..88b690c0484 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java @@ -89,14 +89,6 @@ public class HttpTransportOverSPDY implements HttpTransport return requestHeaders; } - - @Override - public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback) - { - // TODO can this be more efficient? - send(null, responseBodyContent, lastContent, callback); - } - @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, final Callback callback) { @@ -165,7 +157,6 @@ public class HttpTransportOverSPDY implements HttpTransport } else if (!lastContent && !hasContent && info == null) throw new IllegalStateException("not lastContent, no content and no responseInfo!"); - } private void sendReply(HttpGenerator.ResponseInfo info, Callback callback, boolean close) From 9c3eedfea8b49e6c9e0c4b249a415721a0ebd9e9 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 31 Jul 2014 13:26:23 +1000 Subject: [PATCH 161/269] Updates to hpack for hpack-09 draft --- .../org/eclipse/jetty/http/HttpField.java | 44 +++- .../org/eclipse/jetty/http/HttpFields.java | 2 +- .../http2/generator/HeadersGenerator.java | 2 +- .../http2/generator/PushPromiseGenerator.java | 2 +- .../jetty/http2/hpack/HpackContext.java | 23 +- .../jetty/http2/hpack/HpackDecoder.java | 235 ++++++++++-------- .../jetty/http2/hpack/HpackEncoder.java | 64 ++--- .../jetty/http2/hpack/MetaDataBuilder.java | 4 +- .../http2/hpack/StaticValueHttpField.java | 8 + 9 files changed, 200 insertions(+), 184 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index fec510f2cbd..3ac0f333e74 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -20,6 +20,8 @@ package org.eclipse.jetty.http; import java.util.ArrayList; +import org.eclipse.jetty.util.StringUtil; + /* ------------------------------------------------------------ */ /** A HTTP Field */ @@ -67,6 +69,11 @@ public class HttpField return _value; } + public long getLongValue() + { + return StringUtil.toLong(_value); + } + public String[] getValues() { ArrayList<String> list = new ArrayList<>(); @@ -349,19 +356,6 @@ public class HttpField } - - - - - - - - - - - - - @Override public String toString() { @@ -420,4 +414,28 @@ public class HttpField return false; return true; } + + + public static class LongValueHttpField extends HttpField + { + final long _long; + + public LongValueHttpField(HttpHeader header, long value) + { + super(header,Long.toString(value)); + _long=value; + } + + public LongValueHttpField(HttpHeader header, String value) + { + super(header,value); + _long=StringUtil.toLong(value); + } + + @Override + public long getLongValue() + { + return _long; + } + } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index bdc251bdc38..278be78cd83 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -474,7 +474,7 @@ public class HttpFields implements Iterable<HttpField> public long getLongField(String name) throws NumberFormatException { HttpField field = getField(name); - return field==null?-1L:StringUtil.toLong(field.getValue()); + return field==null?-1L:field.getLongValue(); } /** diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index 6aea9cdb6f2..69e52cdabf8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -51,7 +51,7 @@ public class HeadersGenerator extends FrameGenerator if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); - encoder.encode(metaData, lease); + encoder.encode(metaData, lease,Frame.MAX_LENGTH); long length = lease.getTotalLength(); if (length > Frame.MAX_LENGTH) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index db074e682e9..e9196f98829 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -53,7 +53,7 @@ public class PushPromiseGenerator extends FrameGenerator if (promisedStreamId < 0) throw new IllegalArgumentException("Invalid promised stream id: " + promisedStreamId); - encoder.encode(metaData, lease); + encoder.encode(metaData, lease, Frame.MAX_LENGTH); // The promised streamId. int fixedLength = 4; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index d0ac96b2135..659f950ffae 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -117,20 +117,20 @@ public class HpackContext switch(i) { case 2: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.GET),true); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.GET)); break; case 3: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.POST),false); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.POST)); break; case 6: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTP),true); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTP)); break; case 7: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTPS),false); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTPS)); break; case 8: case 11: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1])),true); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1]))); break; case 9: @@ -138,11 +138,11 @@ public class HpackContext case 12: case 13: case 14: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1])),false); + entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1]))); break; default: - entry=new StaticEntry(i,new HttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1]),true); + entry=new StaticEntry(i,new HttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1])); } __staticTable[i]=entry; @@ -412,9 +412,8 @@ public class HpackContext public static class StaticEntry extends Entry { private final byte[] _huffmanValue; - private final boolean _useRefSet; - StaticEntry(int index,HttpField field,boolean useRefSet) + StaticEntry(int index,HttpField field) { super(index,field); String value = field.getValue(); @@ -434,7 +433,6 @@ public class HpackContext } else _huffmanValue=null; - _useRefSet=useRefSet; } @Override @@ -442,11 +440,6 @@ public class HpackContext { return true; } - - public boolean useRefSet() - { - return _useRefSet; - } @Override public byte[] getStaticHuffmanValue() diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index d80b5f550d4..f72ae862e6c 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.TypeUtil; @@ -41,6 +42,7 @@ import org.eclipse.jetty.util.log.Logger; public class HpackDecoder { public static final Logger LOG = Log.getLogger(HpackDecoder.class); + public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 = new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L); private final HpackContext _context; private final MetaDataBuilder _builder; @@ -79,7 +81,7 @@ public class HpackDecoder byte b = buffer.get(); if (b<0) { - // indexed + // 7.1 indexed if the high bit is set int index = NBitInteger.decode(buffer,7); Entry entry=_context.get(index); if (entry==null) @@ -107,126 +109,143 @@ public class HpackDecoder else { // look at the first nibble in detail - int f=(b&0xF0)>>4; + byte f= (byte)((b&0xF0)>>4); String name; HttpHeader header; String value; + + boolean indexed; + int name_index; - if (f<=1 || f>=4) + switch (f) { - // literal - boolean indexed=f>=4; - int bits=indexed?6:4; - boolean huffmanName=false; + case 2: // 7.3 + case 3: // 7.3 + // change table size + int size = NBitInteger.decode(buffer,5); + if (LOG.isDebugEnabled()) + LOG.debug("decode resize="+size); + if (size>_localMaxHeaderTableSize) + throw new IllegalArgumentException(); + _context.resize(size); + continue; - // decode the name - int name_index=NBitInteger.decode(buffer,bits); - if (name_index>0) - { - Entry name_entry=_context.get(name_index); - name=name_entry.getHttpField().getName(); - header=name_entry.getHttpField().getHeader(); - } - else - { - huffmanName = (buffer.get()&0x80)==0x80; - int length = NBitInteger.decode(buffer,7); - _builder.checkSize(length,huffmanName); - if (huffmanName) - name=Huffman.decode(buffer,length); - else - name=toASCIIString(buffer,length); - for (int i=0;i<name.length();i++) - { - char c=name.charAt(i); - if (c>='A'&&c<='Z') - { - throw new BadMessageException(400,"Uppercase header name"); - } - } - header=HttpHeader.CACHE.get(name); - } - - // decode the value - boolean huffmanValue = (buffer.get()&0x80)==0x80; + case 0: // 7.2.2 + case 1: // 7.2.3 + indexed=false; + name_index=NBitInteger.decode(buffer,4); + break; + + + case 4: // 7.2.1 + case 5: // 7.2.1 + case 6: // 7.2.1 + case 7: // 7.2.1 + indexed=true; + name_index=NBitInteger.decode(buffer,6); + break; + + default: + throw new IllegalStateException(); + } + + + boolean huffmanName=false; + + // decode the name + if (name_index>0) + { + Entry name_entry=_context.get(name_index); + name=name_entry.getHttpField().getName(); + header=name_entry.getHttpField().getHeader(); + } + else + { + huffmanName = (buffer.get()&0x80)==0x80; int length = NBitInteger.decode(buffer,7); - _builder.checkSize(length,huffmanValue); - if (huffmanValue) - value=Huffman.decode(buffer,length); + _builder.checkSize(length,huffmanName); + if (huffmanName) + name=Huffman.decode(buffer,length); else - value=toASCIIString(buffer,length); - - // Make the new field - HttpField field; - switch(name) + name=toASCIIString(buffer,length); + for (int i=0;i<name.length();i++) { - case ":method": - HttpMethod method=HttpMethod.CACHE.get(value); - if (method!=null) - field = new StaticValueHttpField(header,name,method.asString(),method); - else - field = new AuthorityHttpField(value); - break; - - case ":status": - Integer code = Integer.valueOf(value); - field = new StaticValueHttpField(header,name,value,code); - break; - - case ":scheme": - HttpScheme scheme=HttpScheme.CACHE.get(value); - if (scheme!=null) - field = new StaticValueHttpField(header,name,scheme.asString(),scheme); - else - field = new AuthorityHttpField(value); - break; - - case ":authority": + char c=name.charAt(i); + if (c>='A'&&c<='Z') + { + throw new BadMessageException(400,"Uppercase header name"); + } + } + header=HttpHeader.CACHE.get(name); + } + + // decode the value + boolean huffmanValue = (buffer.get()&0x80)==0x80; + int length = NBitInteger.decode(buffer,7); + _builder.checkSize(length,huffmanValue); + if (huffmanValue) + value=Huffman.decode(buffer,length); + else + value=toASCIIString(buffer,length); + + // Make the new field + HttpField field; + switch(name) + { + case ":method": + HttpMethod method=HttpMethod.CACHE.get(value); + if (method!=null) + field = new StaticValueHttpField(header,name,method.asString(),method); + else + field = new AuthorityHttpField(value); + break; + + case ":status": + Integer code = Integer.valueOf(value); + field = new StaticValueHttpField(header,name,value,code); + break; + + case ":scheme": + HttpScheme scheme=HttpScheme.CACHE.get(value); + if (scheme!=null) + field = new StaticValueHttpField(header,name,scheme.asString(),scheme); + else field = new AuthorityHttpField(value); - break; - - case ":path": - // TODO is this needed - /* - if (indexed) - field = new StaticValueHttpField(header,name,value,new HttpURI(value)); - else*/ - field = new HttpField(header,name,value); - break; - - default: - field = new HttpField(header,name,value); - break; - } - - if (LOG.isDebugEnabled()) - LOG.debug("decoded '"+field+"' by Lit"+(name_index>0?"IdxName":(huffmanName?"HuffName":"LitName"))+(huffmanValue?"HuffVal":"LitVal")+(indexed?"Idx":"")); - - // emit the field - _builder.emit(field); - - // if indexed - if (indexed) - { - // add to header table - _context.add(field); - } + break; + + case ":authority": + field = new AuthorityHttpField(value); + break; + + case ":path": + field = new HttpField(header,name,value); + break; + + case "content-length": + if ("0".equals(value)) + field = CONTENT_LENGTH_0; + else + field = new HttpField.LongValueHttpField(header,value); + break; + + default: + field = new HttpField(header,name,value); + break; } - else if (f==2) + + if (LOG.isDebugEnabled()) + LOG.debug("decoded '"+field+"' by Lit"+(name_index>0?"IdxName":(huffmanName?"HuffName":"LitName"))+(huffmanValue?"HuffVal":"LitVal")+(indexed?"Idx":"")); + + // emit the field + _builder.emit(field); + + // if indexed + if (indexed) { - // change table size - int size = NBitInteger.decode(buffer,4); - if (LOG.isDebugEnabled()) - LOG.debug("decode resize="+size); - if (size>_localMaxHeaderTableSize) - throw new IllegalArgumentException(); - _context.resize(size); + // add to header table + _context.add(field); } - else if (f==3) - { - if (LOG.isDebugEnabled()) - LOG.debug("unused"); - } + } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index c4c6c7c58db..158cc4e572c 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -42,9 +42,7 @@ public class HpackEncoder private final static EnumSet<HttpHeader> __DO_NOT_HUFFMAN = - EnumSet.of(HttpHeader.COOKIE, - HttpHeader.SET_COOKIE, - HttpHeader.SET_COOKIE2, + EnumSet.of( HttpHeader.AUTHORIZATION, HttpHeader.CONTENT_MD5, HttpHeader.PROXY_AUTHENTICATE, @@ -113,11 +111,11 @@ public class HpackEncoder _localMaxHeaderTableSize=localMaxHeaderTableSize; } - public void encode(MetaData metadata,Lease lease) + // TODO better handling of buffer size + public void encode(MetaData metadata,Lease lease,int buffersize) { - ByteBuffer buffer = lease.acquire(8*1024,false); // TODO make size configurable + ByteBuffer buffer = lease.acquire(buffersize,false); lease.append(buffer,true); - // TODO handle multiple buffers if large size configured. BufferUtil.clearToFill(buffer); encode(buffer,metadata); BufferUtil.flipToFlush(buffer,0); @@ -170,7 +168,7 @@ public class HpackEncoder if (maxHeaderTableSize>_remoteMaxHeaderTableSize) throw new IllegalArgumentException(); buffer.put((byte)0x20); - NBitInteger.encode(buffer,4,maxHeaderTableSize); + NBitInteger.encode(buffer,5,maxHeaderTableSize); _context.resize(maxHeaderTableSize); } @@ -188,87 +186,67 @@ public class HpackEncoder if (entry!=null) { - // Is this as static field - if (entry.isStatic()) - { - // entries like :status: 200 and :method: GET are worthwhile putting into ref set. - // as they are likely to be repeated. - encoding="StaticIndexed"; - int index=_context.index(entry); - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,index); - - // TODO Copy? - // entry=_context.add(entry.getHttpField()); - } - else - { - // So we can emit the index and add the entry to the reference Set - int index=_context.index(entry); - if (p>=0) - encoding="IdxField"+(1+NBitInteger.octectsNeeded(7,index)); - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,index); - } + int index=_context.index(entry); + if (p>=0) + encoding="Indexed"+index; + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,index); } else { // Must be a new entry, so we will have to send literally. - // TODO Strategy decision to make! - // What fields will we put in the reference set and what fields will we huffman encode? - // Let's make these decisions by lookup of known fields HttpHeader header = field.getHeader(); final boolean never_index; final boolean huffman; final boolean indexed; final int name_bits; - final byte mask; if (header==null) { + // unknown header. never_index=false; huffman=true; indexed=true; name_bits = 6; - mask=(byte)0x40; + buffer.put((byte)0x40); } else if (__DO_NOT_INDEX.contains(header)) { + // Non indexed field indexed=false; never_index=__NEVER_INDEX.contains(header); huffman=!__DO_NOT_HUFFMAN.contains(header); name_bits = 4; - mask=never_index?(byte)0x01:(byte)0x00; + buffer.put(never_index?(byte)0x10:(byte)0x00); } else if (header==HttpHeader.CONTENT_LENGTH && field.getValue().length()>1) { + // Non indexed content length for non zero value indexed=false; never_index=false; huffman=true; name_bits = 4; - mask=(byte)0x00; + buffer.put((byte)0x00); } else { + // indexed indexed=true; never_index=false; huffman=!__DO_NOT_HUFFMAN.contains(header); name_bits = 6; - mask=(byte)0x40; + buffer.put((byte)0x40); } - // Add the mask bits - buffer.put(mask); - // Look for a name Index Entry name_entry = _context.get(field.getName()); if (p>=0) { encoding="Lit"+ - ((name_entry==null)?"HuffName":("IdxName"+(_context.index(name_entry)<64?'1':'X')))+ - (huffman?"HuffVal":"LitVal")+ - (indexed?"Idxd":(never_index?"NeverIdx":"")); + ((name_entry==null)?"HuffN":"IdxN")+ + (huffman?"HuffV":"LitV")+ + (indexed?"Idx":(never_index?"!!Idx":"!Idx")); } if (name_entry!=null) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index b7793bc1e92..73ca0f68e22 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -114,9 +114,9 @@ public class MetaDataBuilder break; case ":path": - _path=field.getValue(); + _path = field.getValue(); break; - + default: if (field.getName().charAt(0)!=':') _fields.add(field); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java index 7be683aa78d..39553264753 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java @@ -35,6 +35,14 @@ public class StaticValueHttpField extends HttpField _value=value; } + public StaticValueHttpField(HttpHeader header,String valueString, Object value) + { + super(header,header.asString(),valueString); + if (value==null) + throw new IllegalArgumentException(); + _value=value; + } + public StaticValueHttpField(String name, String valueString, Object value) { super(name,valueString); From 0dbf684298b3702d22a92fe32e62ab1c11b09fce Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 31 Jul 2014 15:22:12 +1000 Subject: [PATCH 162/269] Added alias tests to FileSystemResourceTest --- .../java/org/eclipse/jetty/util/URIUtil.java | 185 +++++++++-------- .../jetty/util/resource/FileResource.java | 7 +- .../jetty/util/resource/PathResource.java | 27 +-- .../jetty/util/resource/FileResourceTest.java | 53 ----- ...eTest.java => FileSystemResourceTest.java} | 190 ++++++++++++++++-- .../jetty/util/resource/PathResourceTest.java | 38 ---- 6 files changed, 278 insertions(+), 222 deletions(-) delete mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileResourceTest.java rename jetty-util/src/test/java/org/eclipse/jetty/util/resource/{AbstractFSResourceTest.java => FileSystemResourceTest.java} (71%) delete mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/resource/PathResourceTest.java diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java index ca2013830c2..f7175033e0d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java @@ -82,8 +82,7 @@ public class URIUtil byte[] bytes=null; if (buf==null) { - loop: - for (int i=0;i<path.length();i++) + loop: for (int i=0;i<path.length();i++) { char c=path.charAt(i); switch(c) @@ -97,6 +96,8 @@ public class URIUtil case '<': case '>': case ' ': + case '[': + case ']': buf=new StringBuilder(path.length()*2); break loop; default: @@ -106,103 +107,111 @@ public class URIUtil buf=new StringBuilder(path.length()*2); break loop; } - } } if (buf==null) return null; } - - synchronized(buf) + + if (bytes!=null) { - if (bytes!=null) + for (int i=0;i<bytes.length;i++) { - for (int i=0;i<bytes.length;i++) + byte c=bytes[i]; + switch(c) { - byte c=bytes[i]; - switch(c) - { - case '%': - buf.append("%25"); - continue; - case '?': - buf.append("%3F"); - continue; - case ';': - buf.append("%3B"); - continue; - case '#': - buf.append("%23"); - continue; - case '"': - buf.append("%22"); - continue; - case '\'': - buf.append("%27"); - continue; - case '<': - buf.append("%3C"); - continue; - case '>': - buf.append("%3E"); - continue; - case ' ': - buf.append("%20"); - continue; - default: - if (c<0) - { - buf.append('%'); - TypeUtil.toHex(c,buf); - } - else - buf.append((char)c); - continue; - } - } - - } - else - { - for (int i=0;i<path.length();i++) - { - char c=path.charAt(i); - switch(c) - { - case '%': - buf.append("%25"); - continue; - case '?': - buf.append("%3F"); - continue; - case ';': - buf.append("%3B"); - continue; - case '#': - buf.append("%23"); - continue; - case '"': - buf.append("%22"); - continue; - case '\'': - buf.append("%27"); - continue; - case '<': - buf.append("%3C"); - continue; - case '>': - buf.append("%3E"); - continue; - case ' ': - buf.append("%20"); - continue; - default: - buf.append(c); - continue; - } + case '%': + buf.append("%25"); + continue; + case '?': + buf.append("%3F"); + continue; + case ';': + buf.append("%3B"); + continue; + case '#': + buf.append("%23"); + continue; + case '"': + buf.append("%22"); + continue; + case '\'': + buf.append("%27"); + continue; + case '<': + buf.append("%3C"); + continue; + case '>': + buf.append("%3E"); + continue; + case ' ': + buf.append("%20"); + continue; + case '[': + buf.append("%5B"); + continue; + case ']': + buf.append("%5D"); + continue; + default: + if (c<0) + { + buf.append('%'); + TypeUtil.toHex(c,buf); + } + else + buf.append((char)c); + continue; } } } + else + { + for (int i=0;i<path.length();i++) + { + char c=path.charAt(i); + switch(c) + { + case '%': + buf.append("%25"); + continue; + case '?': + buf.append("%3F"); + continue; + case ';': + buf.append("%3B"); + continue; + case '#': + buf.append("%23"); + continue; + case '"': + buf.append("%22"); + continue; + case '\'': + buf.append("%27"); + continue; + case '<': + buf.append("%3C"); + continue; + case '>': + buf.append("%3E"); + continue; + case ' ': + buf.append("%20"); + continue; + case '[': + buf.append("%5B"); + continue; + case ']': + buf.append("%5D"); + continue; + default: + buf.append(c); + continue; + } + } + } + return buf; } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java index 412ffb94e93..ccd03a0a89d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java @@ -46,9 +46,7 @@ import org.eclipse.jetty.util.log.Logger; * insensitivity). By default this is turned on, or it can be controlled * by calling the static method @see FileResource#setCheckAliases(boolean) * - * @deprecated use {@link PathResource} instead */ -@Deprecated public class FileResource extends Resource { private static final Logger LOG = Log.getLogger(FileResource.class); @@ -119,7 +117,7 @@ public class FileResource extends Resource } /* -------------------------------------------------------- */ - FileResource(File file) + public FileResource(File file) { _file=file; _uri=normalizeURI(_file,_file.toURI()); @@ -155,7 +153,8 @@ public class FileResource extends Resource URI alias=new File(can).toURI(); // Have to encode the path as File.toURI does not! - return new URI("file://"+URIUtil.encodePath(alias.getPath())); + String uri="file://"+URIUtil.encodePath(alias.getPath()); + return new URI(uri); } } catch(Exception e) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java index 5702052fd8d..5d63471c2f4 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java @@ -49,10 +49,10 @@ import org.eclipse.jetty.util.log.Logger; public class PathResource extends Resource { private static final Logger LOG = Log.getLogger(PathResource.class); + private final static LinkOption NO_FOLLOW_OPTIONS[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; private final Path path; private final URI uri; - private LinkOption linkOptions[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; public PathResource(File file) { @@ -179,7 +179,7 @@ public class PathResource extends Resource @Override public boolean exists() { - return Files.exists(path,linkOptions); + return Files.exists(path,NO_FOLLOW_OPTIONS); } @Override @@ -188,11 +188,6 @@ public class PathResource extends Resource return path.toFile(); } - public boolean getFollowLinks() - { - return (linkOptions != null) && (linkOptions.length > 0) && (linkOptions[0] == LinkOption.NOFOLLOW_LINKS); - } - @Override public InputStream getInputStream() throws IOException { @@ -249,7 +244,7 @@ public class PathResource extends Resource @Override public boolean isDirectory() { - return Files.isDirectory(path,linkOptions); + return Files.isDirectory(path,NO_FOLLOW_OPTIONS); } @Override @@ -257,7 +252,7 @@ public class PathResource extends Resource { try { - FileTime ft = Files.getLastModifiedTime(path,linkOptions); + FileTime ft = Files.getLastModifiedTime(path,NO_FOLLOW_OPTIONS); return ft.toMillis(); } catch (IOException e) @@ -342,7 +337,7 @@ public class PathResource extends Resource try { Path result = Files.move(path,destRes.path); - return Files.exists(result,linkOptions); + return Files.exists(result,NO_FOLLOW_OPTIONS); } catch (IOException e) { @@ -369,18 +364,6 @@ public class PathResource extends Resource } } - public void setFollowLinks(boolean followLinks) - { - if (followLinks) - { - linkOptions = new LinkOption[0]; - } - else - { - linkOptions = new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; - } - } - @Override public String toString() { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileResourceTest.java deleted file mode 100644 index 71b02db6caf..00000000000 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileResourceTest.java +++ /dev/null @@ -1,53 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.util.resource; - -import java.io.File; -import java.io.IOException; -import java.net.URI; - -import org.junit.Ignore; -import org.junit.Test; - -public class FileResourceTest extends AbstractFSResourceTest -{ - @Override - public Resource newResource(URI uri) throws IOException - { - return new FileResource(uri); - } - - @Override - public Resource newResource(File file) throws IOException - { - return new FileResource(file); - } - - @Ignore("Cannot get null to be seen by FileResource") - @Test - public void testExist_BadNull() throws Exception - { - } - - @Ignore("Validation shouldn't be done in FileResource") - @Test - public void testExist_BadNullX() throws Exception - { - } -} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java similarity index 71% rename from jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java rename to jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java index 7d810fe662f..65e89dad527 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java @@ -29,6 +29,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URL; import java.nio.ByteBuffer; @@ -39,8 +40,11 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; +import javax.management.RuntimeErrorException; + import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.OS; @@ -49,15 +53,78 @@ import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.CollectionAssert; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; -public abstract class AbstractFSResourceTest +@RunWith(Parameterized.class) +public class FileSystemResourceTest { @Rule public TestingDir testdir = new TestingDir(); + + private final Class<? extends Resource> _class; - public abstract Resource newResource(URI uri) throws IOException; + @Parameters + public static Collection<Object[]> data() + { + List<Object[]> data = new ArrayList<>(); + data.add(new Class<?>[]{FileResource.class}); + data.add(new Class<?>[]{PathResource.class}); + return data; + } + + public FileSystemResourceTest(Class<? extends Resource> test) + { + _class=test; + } + + + public Resource newResource(URI uri) throws Exception + { + try + { + return _class.getConstructor(URI.class).newInstance(uri); + } + catch(InvocationTargetException e) + { + try + { + throw e.getTargetException(); + } + catch(Exception|Error ex) + { + throw ex; + } + catch(Throwable th) + { + throw new Error(th); + } + } + } - public abstract Resource newResource(File file) throws IOException; + public Resource newResource(File file) throws Exception + { + try + { + return _class.getConstructor(File.class).newInstance(file); + } + catch(InvocationTargetException e) + { + try + { + throw e.getTargetException(); + } + catch(Exception|Error ex) + { + throw ex; + } + catch(Throwable th) + { + throw new Error(th); + } + } + } private URI createEmptyFile(String name) throws IOException { @@ -361,11 +428,96 @@ public abstract class AbstractFSResourceTest // Access to the same resource, but via a symlink means that they are not equivalent assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false)); - assertThat("foo.alias", resFoo.getAlias(), nullValue()); - assertThat("bar.alias", resBar.getAlias(), is(foo.toUri())); + assertThat("foo !alias", resFoo.getAlias(), nullValue()); + assertThat(newResource(resFoo.getURI()).getAlias(), nullValue()); + assertThat(newResource(resFoo.getFile()).getAlias(), nullValue()); + + assertThat("bar alias", resBar.getAlias(), is(foo.toUri())); + assertThat(newResource(resBar.getURI()).getAlias(), is(foo.toUri())); + assertThat(newResource(resBar.getFile()).getAlias(), is(foo.toUri())); } } + + @Test + public void testCaseInsensitiveAlias() throws Exception + { + File dir = testdir.getDir(); + Path path = new File(dir, "file").toPath(); + Files.createFile(path); + + try (Resource base = newResource(testdir.getDir())) + { + Resource resource = base.addPath("file"); + + assertThat("!alias", resource.getAlias(), nullValue()); + assertThat(newResource(resource.getURI()).getAlias(), nullValue()); + assertThat(newResource(resource.getFile()).getAlias(), nullValue()); + + Resource alias = base.addPath("FILE"); + if (alias.exists()) + { + // If it exists, it must be an alias + assertThat(alias.getAlias(), is(path.toUri())); + assertThat(newResource(alias.getURI()).getAlias(), is(path.toUri())); + assertThat(newResource(alias.getFile()).getAlias(), is(path.toUri())); + } + } + } + + @Test + public void testCase8dot3Alias() throws Exception + { + File dir = testdir.getDir(); + Path path = new File(dir, "TextFile.Long.txt").toPath(); + Files.createFile(path); + + try (Resource base = newResource(testdir.getDir())) + { + Resource resource = base.addPath("TextFile.Long.txt"); + + assertThat("!alias", resource.getAlias(), nullValue()); + assertThat(newResource(resource.getURI()).getAlias(), nullValue()); + assertThat(newResource(resource.getFile()).getAlias(), nullValue()); + + Resource alias = base.addPath("TEXTFI~1.TXT"); + if (alias.exists()) + { + // If it exists, it must be an alias + assertThat(alias.getAlias(), is(path.toUri())); + assertThat(newResource(alias.getURI()).getAlias(), is(path.toUri())); + assertThat(newResource(alias.getFile()).getAlias(), is(path.toUri())); + } + } + } + + @Test + public void testCaseNTParamAlias() throws Exception + { + File dir = testdir.getDir(); + Path path = new File(dir, "file").toPath(); + Files.createFile(path); + + try (Resource base = newResource(testdir.getDir())) + { + Resource resource = base.addPath("file"); + + assertThat("!alias", resource.getAlias(), nullValue()); + assertThat(newResource(resource.getURI()).getAlias(), nullValue()); + assertThat(newResource(resource.getFile()).getAlias(), nullValue()); + + Resource alias = base.addPath("file::$DATA"); + if (alias.exists()) + { + // If it exists, it must be an alias + assertThat(alias.getAlias(), is(path.toUri())); + assertThat(newResource(alias.getURI()).getAlias(), is(path.toUri())); + assertThat(newResource(alias.getFile()).getAlias(), is(path.toUri())); + } + } + } + + @Test public void testSemicolon() throws Exception { @@ -460,42 +612,46 @@ public abstract class AbstractFSResourceTest } @Test - public void testExist_BadNull() throws Exception + public void testExist_BadURINull() throws Exception { createEmptyFile("a.jsp"); try { // request with null at end - URI ref = testdir.getDir().toURI().resolve("a.jsp%00"); - assertThat("Null URI",ref,notNullValue()); + URI uri = testdir.getDir().toURI().resolve("a.jsp%00"); + assertThat("Null URI",uri,notNullValue()); - newResource(ref); - fail("Should have thrown " + InvalidPathException.class); + Resource r = newResource(uri); + + // if we have r, then it better not exist + assertFalse(r.exists()); } catch (InvalidPathException e) { - // Expected path + // Exception is acceptable } } @Test - public void testExist_BadNullX() throws Exception + public void testExist_BadURINullX() throws Exception { createEmptyFile("a.jsp"); try { // request with null and x at end - URI ref = testdir.getDir().toURI().resolve("a.jsp%00x"); - assertThat("NullX URI",ref,notNullValue()); + URI uri = testdir.getDir().toURI().resolve("a.jsp%00x"); + assertThat("NullX URI",uri,notNullValue()); - newResource(ref); - fail("Should have thrown " + InvalidPathException.class); + Resource r = newResource(uri); + + // if we have r, then it better not exist + assertFalse(r.exists()); } catch (InvalidPathException e) { - // Expected path + // Exception is acceptable } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/PathResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/PathResourceTest.java deleted file mode 100644 index 6e059a68c2a..00000000000 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/PathResourceTest.java +++ /dev/null @@ -1,38 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.util.resource; - -import java.io.File; -import java.io.IOException; -import java.net.URI; - -public class PathResourceTest extends AbstractFSResourceTest -{ - @Override - public Resource newResource(URI uri) throws IOException - { - return new PathResource(uri); - } - - @Override - public Resource newResource(File file) throws IOException - { - return new PathResource(file); - } -} From 971e1f0aaa9b83726c2fc3dbae95730b0b09ff7b Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Thu, 31 Jul 2014 08:41:35 -0700 Subject: [PATCH 163/269] When test failure occurs, give more details --- .../util/resource/FileSystemResourceTest.java | 116 +++++++++++++----- 1 file changed, 84 insertions(+), 32 deletions(-) diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java index 65e89dad527..302bc589fe8 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java @@ -43,14 +43,15 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import javax.management.RuntimeErrorException; - import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.CollectionAssert; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -65,7 +66,7 @@ public class FileSystemResourceTest private final Class<? extends Resource> _class; - @Parameters + @Parameters(name="{0}") public static Collection<Object[]> data() { List<Object[]> data = new ArrayList<>(); @@ -125,6 +126,56 @@ public class FileSystemResourceTest } } } + + private Matcher<Resource> hasNoAlias() + { + return new BaseMatcher<Resource>() + { + @Override + public boolean matches(Object item) + { + final Resource res = (Resource)item; + return res.getAlias() == null; + } + + @Override + public void describeTo(Description description) + { + description.appendText("getAlias should return null"); + } + + @Override + public void describeMismatch(Object item, Description description) + { + description.appendText("was").appendValue(((Resource)item).getAlias()); + } + }; + } + + private Matcher<Resource> isAliasFor(final Resource resource) + { + return new BaseMatcher<Resource>() + { + @Override + public boolean matches(Object item) + { + final Resource alias = (Resource)item; + return alias.getAlias().equals(resource.getURI()); + } + + @Override + public void describeTo(Description description) + { + description.appendText("getAlias should return ").appendValue(resource.getURI()); + } + + @Override + public void describeMismatch(Object item, Description description) + { + description.appendText("was").appendValue(((Resource)item).getAlias()); + } + }; + } private URI createEmptyFile(String name) throws IOException { @@ -425,16 +476,18 @@ public class FileSystemResourceTest Resource resFoo = base.addPath("foo"); Resource resBar = base.addPath("bar"); + assertThat("resFoo.uri", resFoo.getURI(), is(foo.toUri())); + // Access to the same resource, but via a symlink means that they are not equivalent assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false)); - assertThat("foo !alias", resFoo.getAlias(), nullValue()); - assertThat(newResource(resFoo.getURI()).getAlias(), nullValue()); - assertThat(newResource(resFoo.getFile()).getAlias(), nullValue()); + assertThat("resource.alias", resFoo, hasNoAlias()); + assertThat("resource.uri.alias", newResource(resFoo.getURI()), hasNoAlias()); + assertThat("resource.file.alias", newResource(resFoo.getFile()), hasNoAlias()); - assertThat("bar alias", resBar.getAlias(), is(foo.toUri())); - assertThat(newResource(resBar.getURI()).getAlias(), is(foo.toUri())); - assertThat(newResource(resBar.getFile()).getAlias(), is(foo.toUri())); + assertThat("alias", resBar, isAliasFor(resFoo)); + assertThat("uri.alias", newResource(resBar.getURI()), isAliasFor(resFoo)); + assertThat("file.alias", newResource(resBar.getFile()), isAliasFor(resFoo)); } } @@ -450,17 +503,17 @@ public class FileSystemResourceTest { Resource resource = base.addPath("file"); - assertThat("!alias", resource.getAlias(), nullValue()); - assertThat(newResource(resource.getURI()).getAlias(), nullValue()); - assertThat(newResource(resource.getFile()).getAlias(), nullValue()); + assertThat("resource.alias", resource, hasNoAlias()); + assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias()); + assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias()); Resource alias = base.addPath("FILE"); if (alias.exists()) { // If it exists, it must be an alias - assertThat(alias.getAlias(), is(path.toUri())); - assertThat(newResource(alias.getURI()).getAlias(), is(path.toUri())); - assertThat(newResource(alias.getFile()).getAlias(), is(path.toUri())); + assertThat("alias", alias, isAliasFor(resource)); + assertThat("alias.uri", newResource(alias.getURI()), isAliasFor(resource)); + assertThat("alias.file", newResource(alias.getFile()), isAliasFor(resource)); } } } @@ -476,17 +529,17 @@ public class FileSystemResourceTest { Resource resource = base.addPath("TextFile.Long.txt"); - assertThat("!alias", resource.getAlias(), nullValue()); - assertThat(newResource(resource.getURI()).getAlias(), nullValue()); - assertThat(newResource(resource.getFile()).getAlias(), nullValue()); + assertThat("resource.alias", resource, hasNoAlias()); + assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias()); + assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias()); Resource alias = base.addPath("TEXTFI~1.TXT"); if (alias.exists()) { // If it exists, it must be an alias - assertThat(alias.getAlias(), is(path.toUri())); - assertThat(newResource(alias.getURI()).getAlias(), is(path.toUri())); - assertThat(newResource(alias.getFile()).getAlias(), is(path.toUri())); + assertThat("alias", alias, isAliasFor(resource)); + assertThat("alias.uri", newResource(alias.getURI()), isAliasFor(resource)); + assertThat("alias.file", newResource(alias.getFile()), isAliasFor(resource)); } } } @@ -502,22 +555,21 @@ public class FileSystemResourceTest { Resource resource = base.addPath("file"); - assertThat("!alias", resource.getAlias(), nullValue()); - assertThat(newResource(resource.getURI()).getAlias(), nullValue()); - assertThat(newResource(resource.getFile()).getAlias(), nullValue()); + assertThat("resource.alias", resource, hasNoAlias()); + assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias()); + assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias()); Resource alias = base.addPath("file::$DATA"); if (alias.exists()) { // If it exists, it must be an alias - assertThat(alias.getAlias(), is(path.toUri())); - assertThat(newResource(alias.getURI()).getAlias(), is(path.toUri())); - assertThat(newResource(alias.getFile()).getAlias(), is(path.toUri())); + assertThat("resource.alias", alias, isAliasFor(resource)); + assertThat("resource.uri.alias", newResource(alias.getURI()), isAliasFor(resource)); + assertThat("resource.file.alias", newResource(alias.getFile()), isAliasFor(resource)); } } } - @Test public void testSemicolon() throws Exception { @@ -566,7 +618,7 @@ public class FileSystemResourceTest try (Resource fileres = newResource(refQuoted)) { assertThat("Exists: " + refQuoted,fileres.exists(),is(true)); - assertThat("Alias: " + refQuoted,fileres.getAlias(),nullValue()); + assertThat("Alias: " + refQuoted,fileres,hasNoAlias()); } URI refEncoded = testdir.getDir().toURI().resolve("foo%27s.txt"); @@ -574,7 +626,7 @@ public class FileSystemResourceTest try (Resource fileres = newResource(refEncoded)) { assertThat("Exists: " + refEncoded,fileres.exists(),is(true)); - assertThat("Alias: " + refEncoded,fileres.getAlias(),nullValue()); + assertThat("Alias: " + refEncoded,fileres,hasNoAlias()); } URI refQuoteSpace = testdir.getDir().toURI().resolve("f%20o's.txt"); @@ -582,7 +634,7 @@ public class FileSystemResourceTest try (Resource fileres = newResource(refQuoteSpace)) { assertThat("Exists: " + refQuoteSpace,fileres.exists(),is(true)); - assertThat("Alias: " + refQuoteSpace,fileres.getAlias(),nullValue()); + assertThat("Alias: " + refQuoteSpace,fileres,hasNoAlias()); } URI refEncodedSpace = testdir.getDir().toURI().resolve("f%20o%27s.txt"); @@ -590,7 +642,7 @@ public class FileSystemResourceTest try (Resource fileres = newResource(refEncodedSpace)) { assertThat("Exists: " + refEncodedSpace,fileres.exists(),is(true)); - assertThat("Alias: " + refEncodedSpace,fileres.getAlias(),nullValue()); + assertThat("Alias: " + refEncodedSpace,fileres,hasNoAlias()); } URI refA = testdir.getDir().toURI().resolve("foo's.txt"); From 6048343fee5f5fd9b845ccf12d285c69d5aae182 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Thu, 31 Jul 2014 10:09:53 -0700 Subject: [PATCH 164/269] Enhancing NTFS Stream tests --- .../jetty/util/resource/FileResource.java | 2 +- .../jetty/util/resource/PathResource.java | 53 ++++--- .../util/resource/FileSystemResourceTest.java | 129 ++++++++++++++++-- 3 files changed, 148 insertions(+), 36 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java index ccd03a0a89d..0a90b4e2073 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java @@ -154,7 +154,7 @@ public class FileResource extends Resource URI alias=new File(can).toURI(); // Have to encode the path as File.toURI does not! String uri="file://"+URIUtil.encodePath(alias.getPath()); - return new URI(uri); + return new URI(uri); } } catch(Exception e) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java index 5d63471c2f4..f074d5e1453 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java @@ -52,7 +52,31 @@ public class PathResource extends Resource private final static LinkOption NO_FOLLOW_OPTIONS[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; private final Path path; + private final URI alias; private final URI uri; + + private static final URI toAliasUri(final Path path) + { + Path abs = path; + if (!abs.isAbsolute()) + { + abs = path.toAbsolutePath(); + } + URI providedUri = abs.toUri(); + try + { + URI realUri = abs.toRealPath().toUri(); + if (!providedUri.equals(realUri)) + { + return realUri; + } + } + catch (IOException e) + { + LOG.ignore(e); + } + return null; + } public PathResource(File file) { @@ -61,8 +85,9 @@ public class PathResource extends Resource public PathResource(Path path) { - this.path = path; + this.path = path.toAbsolutePath(); this.uri = this.path.toUri(); + this.alias = toAliasUri(path); } public PathResource(URI uri) throws IOException @@ -96,8 +121,9 @@ public class PathResource extends Resource throw new IOException("Unable to build Path from: " + uri,e); } - this.path = path; + this.path = path.toAbsolutePath(); this.uri = path.toUri(); + this.alias = toAliasUri(path); } public PathResource(URL url) throws IOException, URISyntaxException @@ -109,13 +135,13 @@ public class PathResource extends Resource public Resource addPath(final String subpath) throws IOException, MalformedURLException { String cpath = URIUtil.canonicalPath(subpath); - - if ((cpath == null)||(cpath.length()==0)) + + if ((cpath == null) || (cpath.length() == 0)) throw new MalformedURLException(); if ("/".equals(cpath)) return this; - + // subpaths are always under PathResource // compensate for input subpaths like "/subdir" // where default java.nio.file behavior would be @@ -279,22 +305,7 @@ public class PathResource extends Resource @Override public URI getAlias() { - if (Files.isSymbolicLink(path)) - { - try - { - return path.toRealPath().toUri(); - } - catch (IOException e) - { - LOG.debug(e); - return null; - } - } - else - { - return null; - } + return this.alias; } @Override diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java index 302bc589fe8..9fca622f4df 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java @@ -80,7 +80,6 @@ public class FileSystemResourceTest _class=test; } - public Resource newResource(URI uri) throws Exception { try @@ -147,7 +146,7 @@ public class FileSystemResourceTest @Override public void describeMismatch(Object item, Description description) { - description.appendText("was").appendValue(((Resource)item).getAlias()); + description.appendText("was ").appendValue(((Resource)item).getAlias()); } }; } @@ -159,8 +158,16 @@ public class FileSystemResourceTest @Override public boolean matches(Object item) { - final Resource alias = (Resource)item; - return alias.getAlias().equals(resource.getURI()); + final Resource ritem = (Resource)item; + final URI alias = ritem.getAlias(); + if (alias == null) + { + return ritem == null; + } + else + { + return alias.equals(resource.getURI()); + } } @Override @@ -172,7 +179,7 @@ public class FileSystemResourceTest @Override public void describeMismatch(Object item, Description description) { - description.appendText("was").appendValue(((Resource)item).getAlias()); + description.appendText("was ").appendValue(((Resource)item).getAlias()); } }; } @@ -544,28 +551,122 @@ public class FileSystemResourceTest } } + /** + * NTFS Alternative Data / File Streams. + * <p> + * See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx + */ @Test - public void testCaseNTParamAlias() throws Exception + public void testNTFSFileStreamAlias() throws Exception { File dir = testdir.getDir(); - Path path = new File(dir, "file").toPath(); + Path path = new File(dir, "testfile").toPath(); Files.createFile(path); try (Resource base = newResource(testdir.getDir())) { - Resource resource = base.addPath("file"); + Resource resource = base.addPath("testfile"); assertThat("resource.alias", resource, hasNoAlias()); assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias()); assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias()); - Resource alias = base.addPath("file::$DATA"); - if (alias.exists()) + try { - // If it exists, it must be an alias - assertThat("resource.alias", alias, isAliasFor(resource)); - assertThat("resource.uri.alias", newResource(alias.getURI()), isAliasFor(resource)); - assertThat("resource.file.alias", newResource(alias.getFile()), isAliasFor(resource)); + // Attempt to reference same file, but via NTFS simple stream + Resource alias = base.addPath("testfile:stream"); + if (alias.exists()) + { + // If it exists, it must be an alias + assertThat("resource.alias",alias,isAliasFor(resource)); + assertThat("resource.uri.alias",newResource(alias.getURI()),isAliasFor(resource)); + assertThat("resource.file.alias",newResource(alias.getFile()),isAliasFor(resource)); + } + } + catch (InvalidPathException e) + { + // NTFS filesystem streams are unsupported on some platforms. + assumeNoException(e); + } + } + } + + /** + * NTFS Alternative Data / File Streams. + * <p> + * See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx + */ + @Test + public void testNTFSFileDataStreamAlias() throws Exception + { + File dir = testdir.getDir(); + Path path = new File(dir, "testfile").toPath(); + Files.createFile(path); + + try (Resource base = newResource(testdir.getDir())) + { + Resource resource = base.addPath("testfile"); + + assertThat("resource.alias", resource, hasNoAlias()); + assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias()); + assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias()); + + try + { + // Attempt to reference same file, but via NTFS DATA stream + Resource alias = base.addPath("testfile::$DATA"); + if (alias.exists()) + { + // If it exists, it must be an alias + assertThat("resource.alias",alias,isAliasFor(resource)); + assertThat("resource.uri.alias",newResource(alias.getURI()),isAliasFor(resource)); + assertThat("resource.file.alias",newResource(alias.getFile()),isAliasFor(resource)); + } + } + catch (InvalidPathException e) + { + // NTFS filesystem streams are unsupported on some platforms. + assumeNoException(e); + } + } + } + + /** + * NTFS Alternative Data / File Streams. + * <p> + * See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx + */ + @Test + public void testNTFSFileEncodedDataStreamAlias() throws Exception + { + File dir = testdir.getDir(); + Path path = new File(dir, "testfile").toPath(); + Files.createFile(path); + + try (Resource base = newResource(testdir.getDir())) + { + Resource resource = base.addPath("testfile"); + + assertThat("resource.alias", resource, hasNoAlias()); + assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias()); + assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias()); + + try + { + // Attempt to reference same file, but via NTFS DATA stream + Resource alias = base.addPath("testfile::%24DATA"); + if (alias.exists()) + { + // If it exists, it must be an alias + assertThat("resource.alias",alias,isAliasFor(resource)); + assertThat("resource.uri.alias",newResource(alias.getURI()),isAliasFor(resource)); + assertThat("resource.file.alias",newResource(alias.getFile()),isAliasFor(resource)); + } + } + catch (InvalidPathException e) + { + // NTFS filesystem streams are unsupported on some platforms. + assumeNoException(e); } } } From a0908bf9d860fb835bab7f1912b80dd3a1f2af9d Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Thu, 31 Jul 2014 13:56:02 -0700 Subject: [PATCH 165/269] Minor documentation updates --- .../util/resource/FileSystemResourceTest.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java index 9fca622f4df..d3dcf5beb52 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java @@ -508,12 +508,15 @@ public class FileSystemResourceTest try (Resource base = newResource(testdir.getDir())) { + // Reference to actual resource that exists Resource resource = base.addPath("file"); assertThat("resource.alias", resource, hasNoAlias()); assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias()); assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias()); + // On some case insensitive file systems, lets see if an alternate + // case for the filename results in an alias reference Resource alias = base.addPath("FILE"); if (alias.exists()) { @@ -525,6 +528,12 @@ public class FileSystemResourceTest } } + /** + * Test for Windows feature that exposes 8.3 filename references + * for long filenames. + * <p> + * See: http://support.microsoft.com/kb/142982 + */ @Test public void testCase8dot3Alias() throws Exception { @@ -534,12 +543,15 @@ public class FileSystemResourceTest try (Resource base = newResource(testdir.getDir())) { + // Long filename Resource resource = base.addPath("TextFile.Long.txt"); assertThat("resource.alias", resource, hasNoAlias()); assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias()); assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias()); + // On some versions of Windows, the long filename can be referenced + // via a short 8.3 equivalent filename. Resource alias = base.addPath("TEXTFI~1.TXT"); if (alias.exists()) { @@ -653,7 +665,7 @@ public class FileSystemResourceTest try { - // Attempt to reference same file, but via NTFS DATA stream + // Attempt to reference same file, but via NTFS DATA stream (encoded addPath version) Resource alias = base.addPath("testfile::%24DATA"); if (alias.exists()) { @@ -684,7 +696,7 @@ public class FileSystemResourceTest } catch (Exception e) { - // if unable to create file, no point testing the rest + // if unable to create file, no point testing the rest. // this is the path that Microsoft Windows takes. assumeNoException(e); } @@ -696,6 +708,9 @@ public class FileSystemResourceTest } } + /** + * The most basic access example + */ @Test public void testExist_Normal() throws Exception { From 33435fad3d8e1e12ab85873d842f2f8d580b567a Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Thu, 31 Jul 2014 15:16:44 -0700 Subject: [PATCH 166/269] Making bad alias discovery more obvious (temporary) --- .../java/org/eclipse/jetty/util/resource/PathResource.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java index f074d5e1453..0a5812d0a0f 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java @@ -73,7 +73,8 @@ public class PathResource extends Resource } catch (IOException e) { - LOG.ignore(e); + // TODO: reevaluate severity level + LOG.warn("bad alias ({}) for {}", e.getClass().getName(), e.getMessage()); } return null; } From 3c716a72e74c45d8100e3306fa87ab9e7d2f28e0 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Thu, 31 Jul 2014 16:45:36 -0700 Subject: [PATCH 167/269] Ignoring bad/canonical uri alias --- .../org/eclipse/jetty/util/resource/FileSystemResourceTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java index d3dcf5beb52..5b65894a3d1 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java @@ -629,6 +629,8 @@ public class FileSystemResourceTest Resource alias = base.addPath("testfile::$DATA"); if (alias.exists()) { + assumeThat(alias.getURI().getScheme(), is("http")); + // If it exists, it must be an alias assertThat("resource.alias",alias,isAliasFor(resource)); assertThat("resource.uri.alias",newResource(alias.getURI()),isAliasFor(resource)); From 78165ce5ff166df93d8c10b0b94a17836b9812fa Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 1 Aug 2014 09:51:57 +1000 Subject: [PATCH 168/269] fixed merge --- .../eclipse/jetty/server/HttpConnection.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 56811f675c2..8c5aa76bb05 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -434,11 +434,19 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http @Override public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { - // If we are still expecting a 100 continues when we commit - if (info!=null && _channel.isExpecting100Continue()) - // then we can't be persistent - _generator.setPersistent(false); - if (info==null&&!lastContent&&BufferUtil.isEmpty(content))XXXXX else + if (info == null) + { + if (!lastContent && BufferUtil.isEmpty(content)) + callback.succeeded(); + } + else + { + // If we are still expecting a 100 continues when we commit + if (_channel.isExpecting100Continue()) + // then we can't be persistent + _generator.setPersistent(false); + } + if(_sendCallback.reset(info,content,lastContent,callback)) _sendCallback.iterate(); } From 97d723c516b4a98cd80ecef90b1fcd1bfaabdf08 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 1 Aug 2014 10:45:11 +1000 Subject: [PATCH 169/269] deprecate FileResource --- .../main/java/org/eclipse/jetty/util/resource/FileResource.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java index 0a90b4e2073..10804ddae72 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java @@ -46,7 +46,9 @@ import org.eclipse.jetty.util.log.Logger; * insensitivity). By default this is turned on, or it can be controlled * by calling the static method @see FileResource#setCheckAliases(boolean) * + * @deprecated Use {@link PathResource} */ +@Deprecated public class FileResource extends Resource { private static final Logger LOG = Log.getLogger(FileResource.class); From 6b6267ed31b468ebb254bdd0a59c1505cb7c4a42 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 13:32:56 +0200 Subject: [PATCH 170/269] Updated implementation to draft-14. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 13 +++++++- .../org/eclipse/jetty/http2/frames/Flag.java | 9 ++---- .../org/eclipse/jetty/http2/frames/Frame.java | 5 +-- .../eclipse/jetty/http2/frames/FrameType.java | 4 +-- .../jetty/http2/frames/SettingsFrame.java | 1 + .../jetty/http2/generator/DataGenerator.java | 10 +++--- .../jetty/http2/generator/FrameGenerator.java | 5 +++ .../jetty/http2/generator/Generator.java | 10 ++++-- .../http2/generator/GoAwayGenerator.java | 4 +-- .../http2/generator/HeaderGenerator.java | 17 +++++++++- .../http2/generator/HeadersGenerator.java | 5 +-- .../http2/generator/PushPromiseGenerator.java | 5 +-- .../http2/generator/SettingsGenerator.java | 8 ++--- .../jetty/http2/parser/BodyParser.java | 9 ++---- .../jetty/http2/parser/DataBodyParser.java | 28 ++++------------- .../jetty/http2/parser/HeaderParser.java | 9 +++--- .../jetty/http2/parser/HeadersBodyParser.java | 25 +++------------ .../eclipse/jetty/http2/parser/Parser.java | 2 -- .../http2/parser/PushPromiseBodyParser.java | 27 ++++------------ .../http2/parser/SettingsBodyParser.java | 31 +++++++++++++++++-- .../http2/frames/DataGenerateParseTest.java | 2 +- .../frames/SettingsGenerateParseTest.java | 2 +- .../AbstractHTTP2ServerConnectionFactory.java | 2 +- 23 files changed, 119 insertions(+), 114 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index c1934ee3b40..e548ba629cc 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -176,6 +176,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return false; Map<Integer, Integer> settings = frame.getSettings(); + // TODO: handle other settings if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) { maxStreamCount = settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS); @@ -187,7 +188,17 @@ public abstract class HTTP2Session implements ISession, Parser.Listener int windowSize = settings.get(SettingsFrame.INITIAL_WINDOW_SIZE); flowControl.updateInitialWindowSize(this, windowSize); } - // TODO: handle other settings + if (settings.containsKey(SettingsFrame.MAX_FRAME_SIZE)) + { + int maxFrameSize = settings.get(SettingsFrame.MAX_FRAME_SIZE); + // Spec: check the max frame size is sane. + if (maxFrameSize < Frame.DEFAULT_MAX_LENGTH || maxFrameSize > Frame.MAX_MAX_LENGTH) + { + onConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_max_frame_size"); + return false; + } + generator.setMaxFrameSize(maxFrameSize); + } notifySettings(this, frame); // SPEC: SETTINGS frame MUST be replied. diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java index 0cbdc54ac26..e0f88724542 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java @@ -22,11 +22,8 @@ public interface Flag { public static final int NONE = 0x00; public static final int END_STREAM = 0x01; - public static final int ACK = END_STREAM; - public static final int END_SEGMENT = 0x02; + public static final int ACK = 0x01; public static final int END_HEADERS = 0x04; - public static final int PADDING_LOW = 0x08; - public static final int PADDING_HIGH = 0x10; - public static final int COMPRESS = 0x20; - public static final int PRIORITY = COMPRESS; + public static final int PADDING = 0x08; + public static final int PRIORITY = 0x20; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java index fa2f1945f4d..4a6f36ed4e1 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java @@ -20,8 +20,9 @@ package org.eclipse.jetty.http2.frames; public abstract class Frame { - public static final int HEADER_LENGTH = 8; - public static final int MAX_LENGTH = 0x3F_FF; + public static final int HEADER_LENGTH = 9; + public static final int DEFAULT_MAX_LENGTH = 0x40_00; + public static final int MAX_MAX_LENGTH = 0xFF_FF_FF; private final FrameType type; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java index a84898bd2b8..98b34bfef8a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java @@ -32,9 +32,7 @@ public enum FrameType PING(6), GO_AWAY(7), WINDOW_UPDATE(8), - CONTINUATION(9), - ALTSVC(10), - BLOCKED(11); + CONTINUATION(9); public static FrameType from(int type) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java index 555865fcc64..ef7a53b572e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -26,6 +26,7 @@ public class SettingsFrame extends Frame public static final int ENABLE_PUSH = 2; public static final int MAX_CONCURRENT_STREAMS = 3; public static final int INITIAL_WINDOW_SIZE = 4; + public static final int MAX_FRAME_SIZE = 5; private final Map<Integer, Integer> settings; private final boolean reply; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index 2a6502a86f7..71f59c4d687 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -48,7 +48,8 @@ public class DataGenerator throw new IllegalArgumentException("Invalid stream id: " + streamId); int dataLength = data.remaining(); - if (dataLength <= maxLength && dataLength <= Frame.MAX_LENGTH) + int maxFrameSize = headerGenerator.getMaxFrameSize(); + if (dataLength <= maxLength && dataLength <= maxFrameSize) { // Single frame. generateFrame(lease, streamId, data, last); @@ -58,16 +59,15 @@ public class DataGenerator // Other cases, we need to slice the original buffer into multiple frames. int length = Math.min(maxLength, dataLength); - int dataBytesPerFrame = Frame.MAX_LENGTH; - int frames = length / dataBytesPerFrame; - if (frames * dataBytesPerFrame != length) + int frames = length / maxFrameSize; + if (frames * maxFrameSize != length) ++frames; int begin = data.position(); int end = data.limit(); for (int i = 1; i <= frames; ++i) { - int limit = begin + Math.min(dataBytesPerFrame * i, length); + int limit = begin + Math.min(maxFrameSize * i, length); data.limit(limit); ByteBuffer slice = data.slice(); data.position(limit); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java index 763d6ed703b..a21c742d377 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java @@ -39,4 +39,9 @@ public abstract class FrameGenerator { return headerGenerator.generate(lease, frameType, Frame.HEADER_LENGTH + length, length, flags, streamId); } + + public int getMaxFrameSize() + { + return headerGenerator.getMaxFrameSize(); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index a4a3591540f..d271ae0ca1d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -28,6 +28,7 @@ public class Generator { private final ByteBufferPool byteBufferPool; private final int headerTableSize; + private final HeaderGenerator headerGenerator; private final FrameGenerator[] generators; private final DataGenerator dataGenerator; @@ -41,7 +42,7 @@ public class Generator this.byteBufferPool = byteBufferPool; this.headerTableSize = headerTableSize; - HeaderGenerator headerGenerator = new HeaderGenerator(); + headerGenerator = new HeaderGenerator(); HpackEncoder encoder = new HpackEncoder(headerTableSize); this.generators = new FrameGenerator[FrameType.values().length]; @@ -54,8 +55,6 @@ public class Generator this.generators[FrameType.GO_AWAY.getType()] = new GoAwayGenerator(headerGenerator); this.generators[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateGenerator(headerGenerator); this.generators[FrameType.CONTINUATION.getType()] = null; // TODO - this.generators[FrameType.ALTSVC.getType()] = null; // TODO - this.generators[FrameType.BLOCKED.getType()] = null; // TODO this.dataGenerator = new DataGenerator(headerGenerator); } @@ -70,6 +69,11 @@ public class Generator return headerTableSize; } + public void setMaxFrameSize(int maxFrameSize) + { + headerGenerator.setMaxFrameSize(maxFrameSize); + } + public void control(ByteBufferPool.Lease lease, Frame frame) { generators[frame.getType().getType()].generate(lease, frame); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index e88aa611659..7e2ab6feeed 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -50,8 +50,8 @@ public class GoAwayGenerator extends FrameGenerator // The last streamId + the error code. int fixedLength = 4 + 4; - // Make sure we don't exceed the frame max length. - int maxPayloadLength = Frame.MAX_LENGTH - fixedLength; + // Make sure we don't exceed the default frame max length. + int maxPayloadLength = Frame.DEFAULT_MAX_LENGTH - fixedLength; if (payload != null && payload.length > maxPayloadLength) payload = Arrays.copyOfRange(payload, 0, maxPayloadLength); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java index 5c74d58e118..d2977e81940 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java @@ -20,18 +20,33 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.io.ByteBufferPool; public class HeaderGenerator { + private int maxFrameSize = Frame.DEFAULT_MAX_LENGTH; + public ByteBuffer generate(ByteBufferPool.Lease lease, FrameType frameType, int capacity, int length, int flags, int streamId) { ByteBuffer header = lease.acquire(capacity, true); - header.putShort((short)length); + header.put((byte)((length & 0x00_FF_00_00) >>> 16)); + header.put((byte)((length & 0x00_00_FF_00) >>> 8)); + header.put((byte)((length & 0x00_00_00_FF))); header.put((byte)frameType.getType()); header.put((byte)flags); header.putInt(streamId); return header; } + + public int getMaxFrameSize() + { + return maxFrameSize; + } + + public void setMaxFrameSize(int maxFrameSize) + { + this.maxFrameSize = maxFrameSize; + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index 69e52cdabf8..67bb72d6ab2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -51,10 +51,11 @@ public class HeadersGenerator extends FrameGenerator if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); - encoder.encode(metaData, lease,Frame.MAX_LENGTH); + int maxFrameSize = getMaxFrameSize(); + encoder.encode(metaData, lease, maxFrameSize); long length = lease.getTotalLength(); - if (length > Frame.MAX_LENGTH) + if (length > maxFrameSize) throw new IllegalArgumentException("Invalid headers, too big"); int flags = Flag.END_HEADERS; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index e9196f98829..5b5f025210f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -53,13 +53,14 @@ public class PushPromiseGenerator extends FrameGenerator if (promisedStreamId < 0) throw new IllegalArgumentException("Invalid promised stream id: " + promisedStreamId); - encoder.encode(metaData, lease, Frame.MAX_LENGTH); + int maxFrameSize = getMaxFrameSize(); + encoder.encode(metaData, lease, maxFrameSize); // The promised streamId. int fixedLength = 4; long length = lease.getTotalLength(); - if (length > Frame.MAX_LENGTH - fixedLength) + if (length > maxFrameSize - fixedLength) throw new IllegalArgumentException("Invalid headers, too big"); // Space for the promised streamId. diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index 87e5fbe95c7..0c7795c239f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -44,17 +44,17 @@ public class SettingsGenerator extends FrameGenerator public void generateSettings(ByteBufferPool.Lease lease, Map<Integer, Integer> settings, boolean reply) { - // One byte for the identifier, 4 bytes for the value. - int entryLength = 1 + 4; + // Two bytes for the identifier, four bytes for the value. + int entryLength = 2 + 4; int length = entryLength * settings.size(); - if (length > Frame.MAX_LENGTH) + if (length > getMaxFrameSize()) throw new IllegalArgumentException("Invalid settings, too big"); ByteBuffer header = generateHeader(lease, FrameType.SETTINGS, length, reply ? Flag.ACK : Flag.NONE, 0); for (Map.Entry<Integer, Integer> entry : settings.entrySet()) { - header.put(entry.getKey().byteValue()); + header.putShort(entry.getKey().shortValue()); header.putInt(entry.getValue()); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 016ebf31ba5..257562066c0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -59,14 +59,9 @@ public abstract class BodyParser return headerParser.hasFlag(bit); } - protected boolean isPaddingHigh() + protected boolean isPadding() { - return headerParser.hasFlag(Flag.PADDING_HIGH); - } - - protected boolean isPaddingLow() - { - return headerParser.hasFlag(Flag.PADDING_LOW); + return headerParser.hasFlag(Flag.PADDING); } protected boolean isEndStream() diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index a90e17383c0..fdec23d967c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -44,7 +44,7 @@ public class DataBodyParser extends BodyParser @Override protected boolean emptyBody() { - if (isPaddingHigh() || isPaddingLow()) + if (isPadding()) { notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame"); return false; @@ -68,13 +68,9 @@ public class DataBodyParser extends BodyParser return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame"); } length = getBodyLength(); - if (isPaddingHigh()) + if (isPadding()) { - state = State.PADDING_HIGH; - } - else if (isPaddingLow()) - { - state = State.PADDING_LOW; + state = State.PADDING_LENGTH; } else { @@ -82,20 +78,9 @@ public class DataBodyParser extends BodyParser } break; } - case PADDING_HIGH: + case PADDING_LENGTH: { - paddingLength = (buffer.get() & 0xFF) << 8; - --length; - if (length < 1 + 256) - { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame_padding"); - } - state = State.PADDING_LOW; - break; - } - case PADDING_LOW: - { - paddingLength += buffer.get() & 0xFF; + paddingLength = buffer.get() & 0xFF; --length; length -= paddingLength; state = State.DATA; @@ -128,7 +113,6 @@ public class DataBodyParser extends BodyParser } else { - // TODO: check the semantic of Flag.END_SEGMENT. // We got partial data, simulate a smaller frame, and stay in DATA state. if (onData(slice, true)) { @@ -166,6 +150,6 @@ public class DataBodyParser extends BodyParser private enum State { - PREPARE, PADDING_HIGH, PADDING_LOW, DATA, PADDING + PREPARE, PADDING_LENGTH, DATA, PADDING } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java index 00088233665..19fd651a85d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java @@ -59,12 +59,11 @@ public class HeaderParser { case LENGTH: { - int halfShort = buffer.get() & 0xFF; - length = (length << 8) + halfShort; - if (++cursor == 2) + int octect = buffer.get() & 0xFF; + length = (length << 8) + octect; + if (++cursor == 3) { - // First 2 most significant bits MUST be ignored as per specification. - length &= Frame.MAX_LENGTH; + length &= Frame.MAX_MAX_LENGTH; state = State.TYPE; } break; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index e6f08b80955..8552e1cba10 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -87,13 +87,9 @@ public class HeadersBodyParser extends BodyParser length = getBodyLength(); - if (isPaddingHigh()) + if (isPadding()) { - state = State.PADDING_HIGH; - } - else if (isPaddingLow()) - { - state = State.PADDING_LOW; + state = State.PADDING_LENGTH; } else if (hasFlag(Flag.PRIORITY)) { @@ -105,20 +101,9 @@ public class HeadersBodyParser extends BodyParser } break; } - case PADDING_HIGH: + case PADDING_LENGTH: { - paddingLength = (buffer.get() & 0xFF) << 8; - --length; - state = State.PADDING_LOW; - if (length < 1 + 256) - { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame_padding"); - } - break; - } - case PADDING_LOW: - { - paddingLength += buffer.get() & 0xFF; + paddingLength = buffer.get() & 0xFF; --length; length -= paddingLength; state = hasFlag(Flag.PRIORITY) ? State.EXCLUSIVE : State.HEADERS; @@ -235,6 +220,6 @@ public class HeadersBodyParser extends BodyParser private enum State { - PREPARE, PADDING_HIGH, PADDING_LOW, EXCLUSIVE, STREAM_ID, STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING + PREPARE, PADDING_LENGTH, EXCLUSIVE, STREAM_ID, STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 9314291bde3..8b88e3429a6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -62,8 +62,6 @@ public class Parser bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener); bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener); bodyParsers[FrameType.CONTINUATION.getType()] = null; // TODO - bodyParsers[FrameType.ALTSVC.getType()] = null; // TODO - bodyParsers[FrameType.BLOCKED.getType()] = null; // TODO } private void reset() diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java index ff81fd662f5..4fc69a74e3a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -72,13 +72,9 @@ public class PushPromiseBodyParser extends BodyParser length = getBodyLength(); - if (isPaddingHigh()) + if (isPadding()) { - state = State.PADDING_HIGH; - } - else if (isPaddingLow()) - { - state = State.PADDING_LOW; + state = State.PADDING_LENGTH; } else { @@ -86,26 +82,15 @@ public class PushPromiseBodyParser extends BodyParser } break; } - case PADDING_HIGH: + case PADDING_LENGTH: { - paddingLength = (buffer.get() & 0xFF) << 8; - --length; - state = State.PADDING_LOW; - if (length < 1 + 256) - { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame_padding"); - } - break; - } - case PADDING_LOW: - { - paddingLength += buffer.get() & 0xFF; + paddingLength = buffer.get() & 0xFF; --length; length -= paddingLength; state = State.STREAM_ID; if (length < 4) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame_padding"); + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); } break; } @@ -187,6 +172,6 @@ public class PushPromiseBodyParser extends BodyParser private enum State { - PREPARE, PADDING_HIGH, PADDING_LOW, STREAM_ID, STREAM_ID_BYTES, HEADERS, PADDING + PREPARE, PADDING_LENGTH, STREAM_ID, STREAM_ID_BYTES, HEADERS, PADDING } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index 0db05d10bc9..e74ba5eb4b5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -76,13 +76,38 @@ public class SettingsBodyParser extends BodyParser } case SETTING_ID: { - settingId = buffer.get() & 0xFF; - state = State.SETTING_VALUE; + if (buffer.remaining() >= 2) + { + settingId = buffer.getShort() & 0xFF_FF; + state = State.SETTING_VALUE; + length -= 2; + if (length <= 0) + { + return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); + } + } + else + { + cursor = 2; + settingId = 0; + state = State.SETTING_ID_BYTES; + } + break; + } + case SETTING_ID_BYTES: + { + int currByte = buffer.get() & 0xFF; + --cursor; + settingId += currByte << (8 * cursor); --length; if (length <= 0) { return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); } + if (cursor == 0) + { + state = State.SETTING_VALUE; + } break; } case SETTING_VALUE: @@ -145,6 +170,6 @@ public class SettingsBodyParser extends BodyParser private enum State { - PREPARE, SETTING_ID, SETTING_VALUE, SETTING_VALUE_BYTES + PREPARE, SETTING_ID, SETTING_ID_BYTES, SETTING_VALUE, SETTING_VALUE_BYTES } } diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index cbcf0b62c2c..de5fae0d9a4 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -72,7 +72,7 @@ public class DataGenerateParseTest { ByteBuffer content = ByteBuffer.wrap(largeContent); List<DataFrame> frames = testGenerateParse(content); - Assert.assertEquals(9, frames.size()); + Assert.assertEquals(8, frames.size()); ByteBuffer aggregate = ByteBuffer.allocate(content.remaining()); for (int i = 1; i <= frames.size(); ++i) { diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index 5d417b09192..b4eecd4efb5 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -123,7 +123,7 @@ public class SettingsGenerateParseTest generator.generateSettings(lease, settings1, true); // Modify the length of the frame to make it invalid ByteBuffer bytes = lease.getByteBuffers().get(0); - bytes.putShort(0, (short)(bytes.getShort(0) - 1)); + bytes.putShort(1, (short)(bytes.getShort(1) - 1)); for (ByteBuffer buffer : lease.getByteBuffers()) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index c21492e26c3..a0a99acb421 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -42,7 +42,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne public AbstractHTTP2ServerConnectionFactory() { - super("h2-12"); + super("h2-14"); } public int getMaxHeaderTableSize() From 3283232f026de987210f95de010e3a299e38496f Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 14:02:11 +0200 Subject: [PATCH 171/269] Added initial support for parsing CONTINUATION frames, and nothing more. --- .../http2/parser/ContinuationBodyParser.java | 46 +++++++++++++++++++ .../eclipse/jetty/http2/parser/Parser.java | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java new file mode 100644 index 00000000000..b70983e4230 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java @@ -0,0 +1,46 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.MetaData; + +public class ContinuationBodyParser extends BodyParser +{ + private final HeaderBlockParser headerBlockParser; + + public ContinuationBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser) + { + super(headerParser, listener); + this.headerBlockParser = headerBlockParser; + } + + @Override + public Result parse(ByteBuffer buffer) + { + MetaData metaData = headerBlockParser.parse(buffer, getBodyLength()); + if (metaData != null) + { + // TODO: CONTINUATION frames are not supported for now, we just parse them to keep HPACK happy. + return Result.ASYNC; + } + return Result.PENDING; + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 8b88e3429a6..d84002daeee 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -61,7 +61,7 @@ public class Parser bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener); bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener); bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener); - bodyParsers[FrameType.CONTINUATION.getType()] = null; // TODO + bodyParsers[FrameType.CONTINUATION.getType()] = new ContinuationBodyParser(headerParser, listener, headerBlockParser); } private void reset() From 168a8f7dbfe11e80c9833b4a3bd4fbcc0cc82d66 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 15:01:03 +0200 Subject: [PATCH 172/269] Reporting FRAME_SIZE_ERROR in case wrong frame lengths. --- .../org/eclipse/jetty/http2/parser/DataBodyParser.java | 2 +- .../eclipse/jetty/http2/parser/GoAwayBodyParser.java | 10 +++++----- .../eclipse/jetty/http2/parser/HeadersBodyParser.java | 8 ++++---- .../eclipse/jetty/http2/parser/PriorityBodyParser.java | 2 +- .../jetty/http2/parser/PushPromiseBodyParser.java | 4 ++-- .../eclipse/jetty/http2/parser/ResetBodyParser.java | 2 +- .../eclipse/jetty/http2/parser/SettingsBodyParser.java | 6 +++--- .../jetty/http2/parser/WindowUpdateBodyParser.java | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index fdec23d967c..cb846d38d1f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -87,7 +87,7 @@ public class DataBodyParser extends BodyParser loop = length == 0; if (length < 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame_padding"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_data_frame_padding"); } break; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java index 9b01f517f6a..b9631b22128 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java @@ -69,7 +69,7 @@ public class GoAwayBodyParser extends BodyParser length -= 4; if (length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } } else @@ -87,7 +87,7 @@ public class GoAwayBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } if (cursor == 0) { @@ -95,7 +95,7 @@ public class GoAwayBodyParser extends BodyParser state = State.ERROR; if (length == 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } } break; @@ -109,7 +109,7 @@ public class GoAwayBodyParser extends BodyParser length -= 4; if (length < 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } if (length == 0) { @@ -131,7 +131,7 @@ public class GoAwayBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } if (cursor == 0) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 8552e1cba10..c6b5112e932 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -110,7 +110,7 @@ public class HeadersBodyParser extends BodyParser loop = length == 0; if (length < 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame_padding"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_headers_frame_padding"); } break; } @@ -133,7 +133,7 @@ public class HeadersBodyParser extends BodyParser state = State.WEIGHT; if (length < 1) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_headers_frame"); } } else @@ -151,7 +151,7 @@ public class HeadersBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_headers_frame"); } if (cursor == 0) { @@ -159,7 +159,7 @@ public class HeadersBodyParser extends BodyParser state = State.WEIGHT; if (length < 1) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_headers_frame"); } } break; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index 1389e1df168..6700db99790 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -59,7 +59,7 @@ public class PriorityBodyParser extends BodyParser int length = getBodyLength(); if (length != 5) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_priority_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_priority_frame"); } state = State.EXCLUSIVE; break; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java index 4fc69a74e3a..2a30606c4c3 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -90,7 +90,7 @@ public class PushPromiseBodyParser extends BodyParser state = State.STREAM_ID; if (length < 4) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_push_promise_frame"); } break; } @@ -119,7 +119,7 @@ public class PushPromiseBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_push_promise_frame"); } if (cursor == 0) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java index 15c1e8b1bbc..f85024a9b48 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java @@ -57,7 +57,7 @@ public class ResetBodyParser extends BodyParser int length = getBodyLength(); if (length != 4) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_rst_stream_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_rst_stream_frame"); } state = State.ERROR; break; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index e74ba5eb4b5..aae2d988761 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -83,7 +83,7 @@ public class SettingsBodyParser extends BodyParser length -= 2; if (length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); } } else @@ -102,7 +102,7 @@ public class SettingsBodyParser extends BodyParser --length; if (length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); } if (cursor == 0) { @@ -139,7 +139,7 @@ public class SettingsBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); } if (cursor == 0) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java index c64486c8057..3fd9377d0ae 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java @@ -52,7 +52,7 @@ public class WindowUpdateBodyParser extends BodyParser int length = getBodyLength(); if (length != 4) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_window_update_frame"); + return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_window_update_frame"); } state = State.WINDOW_DELTA; break; From 67fd213263ec05984adc6218898c2ba93c809aae Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 15:03:49 +0200 Subject: [PATCH 173/269] Moved http2.parser.ErrorCode to http2.ErrorCodes. --- .../org/eclipse/jetty/http2/client/HTTP2Client.java | 6 +++--- .../jetty/http2/client/HTTP2ClientSession.java | 4 ++-- .../eclipse/jetty/http2/client/StreamResetTest.java | 8 ++++---- .../{parser/ErrorCode.java => ErrorCodes.java} | 4 ++-- .../java/org/eclipse/jetty/http2/HTTP2Session.java | 11 +++++------ .../java/org/eclipse/jetty/http2/HTTP2Stream.java | 3 +-- .../org/eclipse/jetty/http2/parser/BodyParser.java | 3 ++- .../eclipse/jetty/http2/parser/DataBodyParser.java | 7 ++++--- .../jetty/http2/parser/GoAwayBodyParser.java | 11 ++++++----- .../jetty/http2/parser/HeadersBodyParser.java | 13 +++++++------ .../java/org/eclipse/jetty/http2/parser/Parser.java | 5 +++-- .../eclipse/jetty/http2/parser/PingBodyParser.java | 5 +++-- .../eclipse/jetty/http2/parser/PrefaceParser.java | 3 ++- .../jetty/http2/parser/PriorityBodyParser.java | 5 +++-- .../jetty/http2/parser/PushPromiseBodyParser.java | 9 +++++---- .../eclipse/jetty/http2/parser/ResetBodyParser.java | 5 +++-- .../eclipse/jetty/http2/parser/ServerParser.java | 3 ++- .../jetty/http2/parser/SettingsBodyParser.java | 9 +++++---- .../jetty/http2/parser/WindowUpdateBodyParser.java | 3 ++- .../http2/frames/SettingsGenerateParseTest.java | 4 ++-- .../AbstractHTTP2ServerConnectionFactory.java | 4 ++-- .../eclipse/jetty/http2/server/HTTP2ServerTest.java | 7 +++---- 22 files changed, 71 insertions(+), 61 deletions(-) rename jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/{parser/ErrorCode.java => ErrorCodes.java} (95%) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index ce1996917ad..8e0e4a87201 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -27,13 +27,13 @@ import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; @@ -98,7 +98,7 @@ public class HTTP2Client extends ContainerLifeCycle private void closeConnections() { for (ISession session : sessions) - session.close(ErrorCode.NO_ERROR, null, Callback.Adapter.INSTANCE); + session.close(ErrorCodes.NO_ERROR, null, Callback.Adapter.INSTANCE); sessions.clear(); } @@ -165,7 +165,7 @@ public class HTTP2Client extends ContainerLifeCycle { if (LOG.isDebugEnabled()) LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); - getSession().close(ErrorCode.NO_ERROR, "idle_timeout", closeCallback); + getSession().close(ErrorCodes.NO_ERROR, "idle_timeout", closeCallback); return false; } diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index 7d0affde032..e7644e7df6d 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.http2.client; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.FlowControl; import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.IStream; @@ -25,7 +26,6 @@ import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; @@ -48,7 +48,7 @@ public class HTTP2ClientSession extends HTTP2Session IStream stream = getStream(streamId); if (stream == null) { - ResetFrame reset = new ResetFrame(streamId, ErrorCode.STREAM_CLOSED_ERROR); + ResetFrame reset = new ResetFrame(streamId, ErrorCodes.STREAM_CLOSED_ERROR); reset(reset, disconnectOnFailure()); } else diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java index 2bc87b45a08..abb177bb74c 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java @@ -26,13 +26,13 @@ import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.ResetFrame; -import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.junit.Assert; @@ -51,7 +51,7 @@ public class StreamResetTest extends AbstractTest FuturePromise<Stream> promise = new FuturePromise<>(); client.newStream(requestFrame, promise, new Stream.Listener.Adapter()); Stream stream = promise.get(5, TimeUnit.SECONDS); - ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR); + ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCodes.CANCEL_STREAM_ERROR); stream.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); // After reset the stream should be gone. Assert.assertEquals(0, client.getStreams().size()); @@ -81,7 +81,7 @@ public class StreamResetTest extends AbstractTest FuturePromise<Stream> promise = new FuturePromise<>(); client.newStream(requestFrame, promise, new Stream.Listener.Adapter()); Stream stream = promise.get(5, TimeUnit.SECONDS); - ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR); + ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCodes.CANCEL_STREAM_ERROR); stream.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); @@ -167,7 +167,7 @@ public class StreamResetTest extends AbstractTest }); Stream stream2 = promise2.get(5, TimeUnit.SECONDS); - ResetFrame resetFrame = new ResetFrame(stream1.getId(), ErrorCode.CANCEL_STREAM_ERROR); + ResetFrame resetFrame = new ResetFrame(stream1.getId(), ErrorCodes.CANCEL_STREAM_ERROR); stream1.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); Assert.assertTrue(serverResetLatch.await(5, TimeUnit.SECONDS)); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCodes.java similarity index 95% rename from jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCodes.java index b94a19b8764..2f389a34ff0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ErrorCode.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCodes.java @@ -16,9 +16,9 @@ // ======================================================================== // -package org.eclipse.jetty.http2.parser; +package org.eclipse.jetty.http2; -public interface ErrorCode +public interface ErrorCodes { public static final int NO_ERROR = 0; public static final int PROTOCOL_ERROR = 1; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index e548ba629cc..17a03e2f0d9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -49,7 +49,6 @@ import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; @@ -133,7 +132,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } else { - ResetFrame resetFrame = new ResetFrame(streamId, ErrorCode.STREAM_CLOSED_ERROR); + ResetFrame resetFrame = new ResetFrame(streamId, ErrorCodes.STREAM_CLOSED_ERROR); reset(resetFrame, disconnectOnFailure()); return false; } @@ -194,7 +193,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener // Spec: check the max frame size is sane. if (maxFrameSize < Frame.DEFAULT_MAX_LENGTH || maxFrameSize > Frame.MAX_MAX_LENGTH) { - onConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_max_frame_size"); + onConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_settings_max_frame_size"); return false; } generator.setMaxFrameSize(maxFrameSize); @@ -406,7 +405,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener int maxStreams = maxStreamCount; if (maxStreams >= 0 && currentStreams >= maxStreams) { - reset(new ResetFrame(streamId, ErrorCode.PROTOCOL_ERROR), disconnectOnFailure()); + reset(new ResetFrame(streamId, ErrorCodes.PROTOCOL_ERROR), disconnectOnFailure()); return null; } if (streamCount.compareAndSet(currentStreams, currentStreams + 1)) @@ -427,7 +426,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } else { - close(ErrorCode.PROTOCOL_ERROR, "duplicate_stream", disconnectOnFailure()); + close(ErrorCodes.PROTOCOL_ERROR, "duplicate_stream", disconnectOnFailure()); return null; } } @@ -836,7 +835,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { if (stream != null) stream.close(); - close(ErrorCode.INTERNAL_ERROR, "generator_error", Adapter.INSTANCE); + close(ErrorCodes.INTERNAL_ERROR, "generator_error", Adapter.INSTANCE); callback.failed(x); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index bfa321c4090..d095e2296f9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -29,7 +29,6 @@ import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.ResetFrame; -import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.io.IdleTimeout; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; @@ -133,7 +132,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream // avoid that its idle timeout is rescheduled. close(); - session.reset(new ResetFrame(getId(), ErrorCode.CANCEL_STREAM_ERROR), disconnectOnFailure); + session.reset(new ResetFrame(getId(), ErrorCodes.CANCEL_STREAM_ERROR), disconnectOnFailure); notifyFailure(this, timeout); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 257562066c0..bb538c25bb8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.GoAwayFrame; @@ -50,7 +51,7 @@ public abstract class BodyParser protected boolean emptyBody() { - notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_frame"); + notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_frame"); return false; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index cb846d38d1f..dd1177972b6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.util.BufferUtil; @@ -46,7 +47,7 @@ public class DataBodyParser extends BodyParser { if (isPadding()) { - notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame"); + notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_data_frame"); return false; } return onData(BufferUtil.EMPTY_BUFFER, false); @@ -65,7 +66,7 @@ public class DataBodyParser extends BodyParser // SPEC: wrong streamId is treated as connection error. if (getStreamId() == 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_data_frame"); + return notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_data_frame"); } length = getBodyLength(); if (isPadding()) @@ -87,7 +88,7 @@ public class DataBodyParser extends BodyParser loop = length == 0; if (length < 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_data_frame_padding"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_data_frame_padding"); } break; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java index b9631b22128..89c24eff934 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.GoAwayFrame; public class GoAwayBodyParser extends BodyParser @@ -69,7 +70,7 @@ public class GoAwayBodyParser extends BodyParser length -= 4; if (length <= 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } } else @@ -87,7 +88,7 @@ public class GoAwayBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } if (cursor == 0) { @@ -95,7 +96,7 @@ public class GoAwayBodyParser extends BodyParser state = State.ERROR; if (length == 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } } break; @@ -109,7 +110,7 @@ public class GoAwayBodyParser extends BodyParser length -= 4; if (length < 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } if (length == 0) { @@ -131,7 +132,7 @@ public class GoAwayBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_go_away_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_go_away_frame"); } if (cursor == 0) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index c6b5112e932..471ce6a72c9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; @@ -76,13 +77,13 @@ public class HeadersBodyParser extends BodyParser // SPEC: wrong streamId is treated as connection error. if (getStreamId() == 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_headers_frame"); + return notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_headers_frame"); } // For now we don't support HEADERS frames that don't have END_HEADERS. if (!hasFlag(Flag.END_HEADERS)) { - return notifyConnectionFailure(ErrorCode.INTERNAL_ERROR, "unsupported_headers_frame"); + return notifyConnectionFailure(ErrorCodes.INTERNAL_ERROR, "unsupported_headers_frame"); } length = getBodyLength(); @@ -110,7 +111,7 @@ public class HeadersBodyParser extends BodyParser loop = length == 0; if (length < 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_headers_frame_padding"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_headers_frame_padding"); } break; } @@ -133,7 +134,7 @@ public class HeadersBodyParser extends BodyParser state = State.WEIGHT; if (length < 1) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_headers_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_headers_frame"); } } else @@ -151,7 +152,7 @@ public class HeadersBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_headers_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_headers_frame"); } if (cursor == 0) { @@ -159,7 +160,7 @@ public class HeadersBodyParser extends BodyParser state = State.WEIGHT; if (length < 1) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_headers_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_headers_frame"); } } break; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index d84002daeee..dc447c5be0c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.GoAwayFrame; @@ -95,7 +96,7 @@ public class Parser LOG.debug("Parsing {} frame", FrameType.from(type)); if (type < 0 || type >= bodyParsers.length) { - notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "unknown_frame_type_" + type); + notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "unknown_frame_type_" + type); return false; } BodyParser bodyParser = bodyParsers[type]; @@ -151,7 +152,7 @@ public class Parser catch (Throwable x) { LOG.debug(x); - notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "parser_error: "+x); + notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "parser_error: "+x); return false; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 58fd1207de5..5755a04ce33 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.PingFrame; @@ -53,12 +54,12 @@ public class PingBodyParser extends BodyParser // SPEC: wrong streamId is treated as connection error. if (getStreamId() != 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_ping_frame"); + return notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_ping_frame"); } // SPEC: wrong body length is treated as connection error. if (getBodyLength() != 8) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_ping_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_ping_frame"); } state = State.PAYLOAD; break; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java index 6c5f635681b..92e9d1e9060 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -48,7 +49,7 @@ public class PrefaceParser int currByte = buffer.get(); if (currByte != PREFACE_BYTES[cursor]) { - notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_preface"); + notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_preface"); return false; } ++cursor; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index 6700db99790..1e38223aeb4 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.PriorityFrame; public class PriorityBodyParser extends BodyParser @@ -54,12 +55,12 @@ public class PriorityBodyParser extends BodyParser // SPEC: wrong streamId is treated as connection error. if (getStreamId() == 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_priority_frame"); + return notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_priority_frame"); } int length = getBodyLength(); if (length != 5) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_priority_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_priority_frame"); } state = State.EXCLUSIVE; break; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java index 2a30606c4c3..fedaf0905c6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.PushPromiseFrame; @@ -61,13 +62,13 @@ public class PushPromiseBodyParser extends BodyParser // SPEC: wrong streamId is treated as connection error. if (getStreamId() == 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_push_promise_frame"); + return notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_push_promise_frame"); } // For now we don't support PUSH_PROMISE frames that don't have END_HEADERS. if (!hasFlag(Flag.END_HEADERS)) { - return notifyConnectionFailure(ErrorCode.INTERNAL_ERROR, "unsupported_push_promise_frame"); + return notifyConnectionFailure(ErrorCodes.INTERNAL_ERROR, "unsupported_push_promise_frame"); } length = getBodyLength(); @@ -90,7 +91,7 @@ public class PushPromiseBodyParser extends BodyParser state = State.STREAM_ID; if (length < 4) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_push_promise_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_push_promise_frame"); } break; } @@ -119,7 +120,7 @@ public class PushPromiseBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_push_promise_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_push_promise_frame"); } if (cursor == 0) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java index f85024a9b48..4328ce6d96a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.ResetFrame; public class ResetBodyParser extends BodyParser @@ -52,12 +53,12 @@ public class ResetBodyParser extends BodyParser // SPEC: wrong streamId is treated as connection error. if (getStreamId() == 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_rst_stream_frame"); + return notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_rst_stream_frame"); } int length = getBodyLength(); if (length != 4) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_rst_stream_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_rst_stream_frame"); } state = State.ERROR; break; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java index 5e5754e41b2..44f523925b2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -75,7 +76,7 @@ public class ServerParser extends Parser catch (Throwable x) { LOG.debug(x); - notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "parser_error"); + notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "parser_error"); return false; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index aae2d988761..244021d89d7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.SettingsFrame; @@ -67,7 +68,7 @@ public class SettingsBodyParser extends BodyParser // SPEC: wrong streamId is treated as connection error. if (getStreamId() != 0) { - return notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); + return notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_settings_frame"); } length = getBodyLength(); settings = new HashMap<>(); @@ -83,7 +84,7 @@ public class SettingsBodyParser extends BodyParser length -= 2; if (length <= 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_settings_frame"); } } else @@ -102,7 +103,7 @@ public class SettingsBodyParser extends BodyParser --length; if (length <= 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_settings_frame"); } if (cursor == 0) { @@ -139,7 +140,7 @@ public class SettingsBodyParser extends BodyParser --length; if (cursor > 0 && length <= 0) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_settings_frame"); } if (cursor == 0) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java index 3fd9377d0ae..ec401bc8da1 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; public class WindowUpdateBodyParser extends BodyParser @@ -52,7 +53,7 @@ public class WindowUpdateBodyParser extends BodyParser int length = getBodyLength(); if (length != 4) { - return notifyConnectionFailure(ErrorCode.FRAME_SIZE_ERROR, "invalid_window_update_frame"); + return notifyConnectionFailure(ErrorCodes.FRAME_SIZE_ERROR, "invalid_window_update_frame"); } state = State.WINDOW_DELTA; break; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index b4eecd4efb5..791b2843aba 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -26,9 +26,9 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.SettingsGenerator; -import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -133,7 +133,7 @@ public class SettingsGenerateParseTest } } - Assert.assertEquals(ErrorCode.PROTOCOL_ERROR, errorRef.get()); + Assert.assertEquals(ErrorCodes.PROTOCOL_ERROR, errorRef.get()); } @Test diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index a0a99acb421..023acb263c4 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -20,12 +20,12 @@ package org.eclipse.jetty.http2.server; import java.util.concurrent.Executor; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.ByteBufferPool; @@ -117,7 +117,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne { if (LOG.isDebugEnabled()) LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); - getSession().close(ErrorCode.NO_ERROR, "idle_timeout", closeCallback); + getSession().close(ErrorCodes.NO_ERROR, "idle_timeout", closeCallback); return false; } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 15c0b7996ff..59100a75149 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -28,7 +28,6 @@ import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -40,13 +39,13 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.parser.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; @@ -297,7 +296,7 @@ public class HTTP2ServerTest @Override public boolean onGoAway(GoAwayFrame frame) { - Assert.assertEquals(ErrorCode.FRAME_SIZE_ERROR, frame.getError()); + Assert.assertEquals(ErrorCodes.FRAME_SIZE_ERROR, frame.getError()); latch.countDown(); return false; } @@ -337,7 +336,7 @@ public class HTTP2ServerTest @Override public boolean onGoAway(GoAwayFrame frame) { - Assert.assertEquals(ErrorCode.PROTOCOL_ERROR, frame.getError()); + Assert.assertEquals(ErrorCodes.PROTOCOL_ERROR, frame.getError()); latch.countDown(); return false; } From 89a045855c0524cadbb3919b7648665124d60b04 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 15:04:14 +0200 Subject: [PATCH 174/269] Moved http2.frames.Flag to http2.Flags. --- .../jetty/http2/{frames/Flag.java => Flags.java} | 4 ++-- .../eclipse/jetty/http2/generator/DataGenerator.java | 6 +++--- .../eclipse/jetty/http2/generator/GoAwayGenerator.java | 4 ++-- .../jetty/http2/generator/HeadersGenerator.java | 6 +++--- .../eclipse/jetty/http2/generator/PingGenerator.java | 4 ++-- .../jetty/http2/generator/PriorityGenerator.java | 4 ++-- .../jetty/http2/generator/PushPromiseGenerator.java | 4 ++-- .../eclipse/jetty/http2/generator/ResetGenerator.java | 4 ++-- .../jetty/http2/generator/SettingsGenerator.java | 4 ++-- .../jetty/http2/generator/WindowUpdateGenerator.java | 6 +++--- .../org/eclipse/jetty/http2/parser/BodyParser.java | 6 +++--- .../eclipse/jetty/http2/parser/HeadersBodyParser.java | 10 +++++----- .../org/eclipse/jetty/http2/parser/PingBodyParser.java | 4 ++-- .../jetty/http2/parser/PushPromiseBodyParser.java | 4 ++-- .../eclipse/jetty/http2/parser/SettingsBodyParser.java | 4 ++-- 15 files changed, 37 insertions(+), 37 deletions(-) rename jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/{frames/Flag.java => Flags.java} (94%) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java similarity index 94% rename from jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java index e0f88724542..5124d8ca797 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Flag.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java @@ -16,9 +16,9 @@ // ======================================================================== // -package org.eclipse.jetty.http2.frames; +package org.eclipse.jetty.http2; -public interface Flag +public interface Flags { public static final int NONE = 0x00; public static final int END_STREAM = 0x01; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index 71f59c4d687..1a2c42d31f2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -20,8 +20,8 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.DataFrame; -import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.io.ByteBufferPool; @@ -80,9 +80,9 @@ public class DataGenerator { int length = data.remaining(); - int flags = Flag.NONE; + int flags = Flags.NONE; if (last) - flags |= Flag.END_STREAM; + flags |= Flags.END_STREAM; ByteBuffer header = headerGenerator.generate(lease, FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags, streamId); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index 7e2ab6feeed..9290bcd4680 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -21,7 +21,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; import java.util.Arrays; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.GoAwayFrame; @@ -56,7 +56,7 @@ public class GoAwayGenerator extends FrameGenerator payload = Arrays.copyOfRange(payload, 0, maxPayloadLength); int length = fixedLength + (payload != null ? payload.length : 0); - ByteBuffer header = generateHeader(lease, FrameType.GO_AWAY, length, Flag.NONE, 0); + ByteBuffer header = generateHeader(lease, FrameType.GO_AWAY, length, Flags.NONE, 0); header.putInt(lastStreamId); header.putInt(error); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index 67bb72d6ab2..b7d4c7615e5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -21,7 +21,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -58,9 +58,9 @@ public class HeadersGenerator extends FrameGenerator if (length > maxFrameSize) throw new IllegalArgumentException("Invalid headers, too big"); - int flags = Flag.END_HEADERS; + int flags = Flags.END_HEADERS; if (!contentFollows) - flags |= Flag.END_STREAM; + flags |= Flags.END_STREAM; ByteBuffer header = generateHeader(lease, FrameType.HEADERS, (int)length, flags, streamId); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java index ec5db1a151a..5cc22dd9160 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.PingFrame; @@ -46,7 +46,7 @@ public class PingGenerator extends FrameGenerator if (payload.length != 8) throw new IllegalArgumentException("Invalid payload length: " + payload.length); - ByteBuffer header = generateHeader(lease, FrameType.PING, 8, reply ? Flag.ACK : Flag.NONE, 0); + ByteBuffer header = generateHeader(lease, FrameType.PING, 8, reply ? Flags.ACK : Flags.NONE, 0); header.put(payload); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java index 4ebb52d715f..b10efb4bb82 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.PriorityFrame; @@ -48,7 +48,7 @@ public class PriorityGenerator extends FrameGenerator if (dependentStreamId < 0) throw new IllegalArgumentException("Invalid dependent stream id: " + dependentStreamId); - ByteBuffer header = generateHeader(lease, FrameType.PRIORITY, 5, Flag.NONE, dependentStreamId); + ByteBuffer header = generateHeader(lease, FrameType.PRIORITY, 5, Flags.NONE, dependentStreamId); if (exclusive) streamId |= 0x80_00_00_00; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index 5b5f025210f..ed973ce3b0f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -21,7 +21,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.PushPromiseFrame; @@ -66,7 +66,7 @@ public class PushPromiseGenerator extends FrameGenerator // Space for the promised streamId. length += fixedLength; - int flags = Flag.END_HEADERS; + int flags = Flags.END_HEADERS; ByteBuffer header = generateHeader(lease, FrameType.PUSH_PROMISE, (int)length, flags, streamId); header.putInt(promisedStreamId); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java index 781f29346d0..723457fd6bd 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.ResetFrame; @@ -46,7 +46,7 @@ public class ResetGenerator extends FrameGenerator if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); - ByteBuffer header = generateHeader(lease, FrameType.RST_STREAM, 4, Flag.NONE, streamId); + ByteBuffer header = generateHeader(lease, FrameType.RST_STREAM, 4, Flags.NONE, streamId); header.putInt(error); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index 0c7795c239f..dde019225ff 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -21,7 +21,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; import java.util.Map; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.SettingsFrame; @@ -50,7 +50,7 @@ public class SettingsGenerator extends FrameGenerator if (length > getMaxFrameSize()) throw new IllegalArgumentException("Invalid settings, too big"); - ByteBuffer header = generateHeader(lease, FrameType.SETTINGS, length, reply ? Flag.ACK : Flag.NONE, 0); + ByteBuffer header = generateHeader(lease, FrameType.SETTINGS, length, reply ? Flags.ACK : Flags.NONE, 0); for (Map.Entry<Integer, Integer> entry : settings.entrySet()) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java index e9be713989e..deb66b025b7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.http2.generator; import java.nio.ByteBuffer; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; @@ -57,13 +57,13 @@ public class WindowUpdateGenerator extends FrameGenerator if (both) { - ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flag.NONE, 0); + ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flags.NONE, 0); header.putInt(windowUpdate); BufferUtil.flipToFlush(header, 0); lease.append(header, true); } - ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flag.NONE, streamId); + ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flags.NONE, streamId); header.putInt(windowUpdate); BufferUtil.flipToFlush(header, 0); lease.append(header, true); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index bb538c25bb8..a0151dfb532 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -21,8 +21,8 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.ErrorCodes; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.DataFrame; -import org.eclipse.jetty.http2.frames.Flag; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; @@ -62,12 +62,12 @@ public abstract class BodyParser protected boolean isPadding() { - return headerParser.hasFlag(Flag.PADDING); + return headerParser.hasFlag(Flags.PADDING); } protected boolean isEndStream() { - return headerParser.hasFlag(Flag.END_STREAM); + return headerParser.hasFlag(Flags.END_STREAM); } protected int getStreamId() diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 471ce6a72c9..3a2f6296fb1 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCodes; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.util.BufferUtil; @@ -81,7 +81,7 @@ public class HeadersBodyParser extends BodyParser } // For now we don't support HEADERS frames that don't have END_HEADERS. - if (!hasFlag(Flag.END_HEADERS)) + if (!hasFlag(Flags.END_HEADERS)) { return notifyConnectionFailure(ErrorCodes.INTERNAL_ERROR, "unsupported_headers_frame"); } @@ -92,7 +92,7 @@ public class HeadersBodyParser extends BodyParser { state = State.PADDING_LENGTH; } - else if (hasFlag(Flag.PRIORITY)) + else if (hasFlag(Flags.PRIORITY)) { state = State.EXCLUSIVE; } @@ -107,7 +107,7 @@ public class HeadersBodyParser extends BodyParser paddingLength = buffer.get() & 0xFF; --length; length -= paddingLength; - state = hasFlag(Flag.PRIORITY) ? State.EXCLUSIVE : State.HEADERS; + state = hasFlag(Flags.PRIORITY) ? State.EXCLUSIVE : State.HEADERS; loop = length == 0; if (length < 0) { @@ -211,7 +211,7 @@ public class HeadersBodyParser extends BodyParser private boolean onHeaders(int streamId, int weight, boolean exclusive, MetaData metaData) { PriorityFrame priorityFrame = null; - if (hasFlag(Flag.PRIORITY)) + if (hasFlag(Flags.PRIORITY)) { priorityFrame = new PriorityFrame(streamId, getStreamId(), weight, exclusive); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 5755a04ce33..96ca76aa7a0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -21,7 +21,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.ErrorCodes; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.PingFrame; public class PingBodyParser extends BodyParser @@ -100,7 +100,7 @@ public class PingBodyParser extends BodyParser private Result onPing(byte[] payload) { - PingFrame frame = new PingFrame(payload, hasFlag(Flag.ACK)); + PingFrame frame = new PingFrame(payload, hasFlag(Flags.ACK)); reset(); return notifyPing(frame) ? Result.ASYNC : Result.COMPLETE; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java index fedaf0905c6..d0c0af9eb25 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCodes; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.PushPromiseFrame; public class PushPromiseBodyParser extends BodyParser @@ -66,7 +66,7 @@ public class PushPromiseBodyParser extends BodyParser } // For now we don't support PUSH_PROMISE frames that don't have END_HEADERS. - if (!hasFlag(Flag.END_HEADERS)) + if (!hasFlag(Flags.END_HEADERS)) { return notifyConnectionFailure(ErrorCodes.INTERNAL_ERROR, "unsupported_push_promise_frame"); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index 244021d89d7..5b8cfa61a60 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -23,7 +23,7 @@ import java.util.HashMap; import java.util.Map; import org.eclipse.jetty.http2.ErrorCodes; -import org.eclipse.jetty.http2.frames.Flag; +import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.SettingsFrame; public class SettingsBodyParser extends BodyParser @@ -164,7 +164,7 @@ public class SettingsBodyParser extends BodyParser private Result onSettings(Map<Integer, Integer> settings) { - SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flag.ACK)); + SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK)); reset(); return notifySettings(frame) ? Result.ASYNC : Result.COMPLETE; } From 346b726c47b3f08082b597ad0babaaf4d1d04ab3 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 15:54:12 +0200 Subject: [PATCH 175/269] Taking into account the padding bytes in flow control length. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 9 +++++---- .../eclipse/jetty/http2/frames/DataFrame.java | 18 ++++++++++++++++++ .../jetty/http2/parser/DataBodyParser.java | 14 +++++++++----- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 17a03e2f0d9..789240e0abd 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -116,14 +116,15 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (stream != null) { stream.updateClose(frame.isEndStream(), false); - final int length = frame.remaining(); - flowControl.onDataReceived(this, stream, length); + // The flow control length includes the padding bytes. + final int flowControlLength = frame.remaining() + frame.padding(); + flowControl.onDataReceived(this, stream, flowControlLength); boolean result = stream.process(frame, new Callback.Adapter() { @Override public void succeeded() { - flowControl.onDataConsumed(HTTP2Session.this, stream, length); + flowControl.onDataConsumed(HTTP2Session.this, stream, flowControlLength); } }); if (stream.isClosed()) @@ -405,7 +406,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener int maxStreams = maxStreamCount; if (maxStreams >= 0 && currentStreams >= maxStreams) { - reset(new ResetFrame(streamId, ErrorCodes.PROTOCOL_ERROR), disconnectOnFailure()); + reset(new ResetFrame(streamId, ErrorCodes.REFUSED_STREAM_ERROR), disconnectOnFailure()); return null; } if (streamCount.compareAndSet(currentStreams, currentStreams + 1)) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java index a754577bf60..03377cb1194 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -25,13 +25,20 @@ public class DataFrame extends Frame private final int streamId; private final ByteBuffer data; private final boolean endStream; + private final int padding; public DataFrame(int streamId, ByteBuffer data, boolean endStream) + { + this(streamId, data, endStream, 0); + } + + public DataFrame(int streamId, ByteBuffer data, boolean endStream, int padding) { super(FrameType.DATA); this.streamId = streamId; this.data = data; this.endStream = endStream; + this.padding = padding; } public int getStreamId() @@ -49,11 +56,22 @@ public class DataFrame extends Frame return endStream; } + /** + * @return the number of data bytes remaining. + */ public int remaining() { return data.remaining(); } + /** + * @return the number of bytes used for padding that count towards flow control. + */ + public int padding() + { + return padding; + } + @Override public String toString() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index dd1177972b6..44347454e6b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -50,7 +50,7 @@ public class DataBodyParser extends BodyParser notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_data_frame"); return false; } - return onData(BufferUtil.EMPTY_BUFFER, false); + return onData(BufferUtil.EMPTY_BUFFER, false, 0); } @Override @@ -107,7 +107,9 @@ public class DataBodyParser extends BodyParser { state = State.PADDING; loop = paddingLength == 0; - if (onData(slice, false)) + // Padding bytes include the bytes that define the + // padding length plus the actual padding bytes. + if (onData(slice, false, 1 + paddingLength)) { return Result.ASYNC; } @@ -115,7 +117,9 @@ public class DataBodyParser extends BodyParser else { // We got partial data, simulate a smaller frame, and stay in DATA state. - if (onData(slice, true)) + // No padding for these synthetic frames (even if we have read + // the padding length already), it will be accounted at the end. + if (onData(slice, true, 0)) { return Result.ASYNC; } @@ -143,9 +147,9 @@ public class DataBodyParser extends BodyParser return Result.PENDING; } - private boolean onData(ByteBuffer buffer, boolean fragment) + private boolean onData(ByteBuffer buffer, boolean fragment, int padding) { - DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream()); + DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding); return notifyData(frame); } From cddfa033f066bee5c89abbf6651ba0a7000d2952 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 16:20:20 +0200 Subject: [PATCH 176/269] Implemented handling of SETTINGS_HEADER_TABLE_SIZE configuration property. --- .../java/org/eclipse/jetty/http2/HTTP2Session.java | 10 +++++++++- .../eclipse/jetty/http2/generator/Generator.java | 13 ++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 789240e0abd..0b98d5c2b7d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -176,7 +176,13 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return false; Map<Integer, Integer> settings = frame.getSettings(); - // TODO: handle other settings + if (settings.containsKey(SettingsFrame.HEADER_TABLE_SIZE)) + { + int headerTableSize = settings.get(SettingsFrame.HEADER_TABLE_SIZE); + if (LOG.isDebugEnabled()) + LOG.debug("Updated HPACK header table size to {}", headerTableSize); + generator.setHeaderTableSize(headerTableSize); + } if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) { maxStreamCount = settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS); @@ -197,6 +203,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener onConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_settings_max_frame_size"); return false; } + if (LOG.isDebugEnabled()) + LOG.debug("Updated max frame size to {}", maxFrameSize); generator.setMaxFrameSize(maxFrameSize); } notifySettings(this, frame); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index d271ae0ca1d..105e4d61b98 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -27,8 +27,8 @@ import org.eclipse.jetty.io.ByteBufferPool; public class Generator { private final ByteBufferPool byteBufferPool; - private final int headerTableSize; private final HeaderGenerator headerGenerator; + private final HpackEncoder hpackEncoder; private final FrameGenerator[] generators; private final DataGenerator dataGenerator; @@ -40,17 +40,16 @@ public class Generator public Generator(ByteBufferPool byteBufferPool, int headerTableSize) { this.byteBufferPool = byteBufferPool; - this.headerTableSize = headerTableSize; headerGenerator = new HeaderGenerator(); - HpackEncoder encoder = new HpackEncoder(headerTableSize); + hpackEncoder = new HpackEncoder(headerTableSize); this.generators = new FrameGenerator[FrameType.values().length]; - this.generators[FrameType.HEADERS.getType()] = new HeadersGenerator(headerGenerator, encoder); + this.generators[FrameType.HEADERS.getType()] = new HeadersGenerator(headerGenerator, hpackEncoder); this.generators[FrameType.PRIORITY.getType()] = new PriorityGenerator(headerGenerator); this.generators[FrameType.RST_STREAM.getType()] = new ResetGenerator(headerGenerator); this.generators[FrameType.SETTINGS.getType()] = new SettingsGenerator(headerGenerator); - this.generators[FrameType.PUSH_PROMISE.getType()] = new PushPromiseGenerator(headerGenerator, encoder); + this.generators[FrameType.PUSH_PROMISE.getType()] = new PushPromiseGenerator(headerGenerator, hpackEncoder); this.generators[FrameType.PING.getType()] = new PingGenerator(headerGenerator); this.generators[FrameType.GO_AWAY.getType()] = new GoAwayGenerator(headerGenerator); this.generators[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateGenerator(headerGenerator); @@ -64,9 +63,9 @@ public class Generator return byteBufferPool; } - public int getHeaderTableSize() + public void setHeaderTableSize(int headerTableSize) { - return headerTableSize; + hpackEncoder.setRemoteMaxHeaderTableSize(headerTableSize); } public void setMaxFrameSize(int maxFrameSize) From 7004d719965ae911606e641ba418c233a6e5ad52 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 16:22:36 +0200 Subject: [PATCH 177/269] Reporting FRAME_SIZE_ERROR in case wrong frame lengths. --- .../eclipse/jetty/http2/frames/SettingsGenerateParseTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index 791b2843aba..c23674819ef 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -133,7 +133,7 @@ public class SettingsGenerateParseTest } } - Assert.assertEquals(ErrorCodes.PROTOCOL_ERROR, errorRef.get()); + Assert.assertEquals(ErrorCodes.FRAME_SIZE_ERROR, errorRef.get()); } @Test From 51e4885911a57779e195ddf9a71faed519784875 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 19:03:29 +0200 Subject: [PATCH 178/269] Made HTTP2Client support SSL so that it can be used to test websites that serve HTTP2. --- jetty-http2/http2-client/pom.xml | 5 + .../jetty/http2/client/HTTP2Client.java | 115 +++++++---------- .../client/HTTP2ClientConnectionFactory.java | 118 ++++++++++++++++++ .../eclipse/jetty/http2/client/Client.java | 71 +++++++++++ .../io/ssl/SslClientConnectionFactory.java | 2 +- 5 files changed, 240 insertions(+), 71 deletions(-) create mode 100644 jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java diff --git a/jetty-http2/http2-client/pom.xml b/jetty-http2/http2-client/pom.xml index a509d586ea1..60c4bb96f47 100644 --- a/jetty-http2/http2-client/pom.xml +++ b/jetty-http2/http2-client/pom.xml @@ -49,6 +49,11 @@ <artifactId>http2-common</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-alpn-client</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.eclipse.jetty.toolchain</groupId> diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index 8e0e4a87201..b45a06ad573 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -20,31 +20,30 @@ package org.eclipse.jetty.http2.client; import java.io.IOException; import java.net.InetSocketAddress; -import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; +import java.util.HashMap; +import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; +import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory; import org.eclipse.jetty.http2.ErrorCodes; -import org.eclipse.jetty.http2.HTTP2Connection; -import org.eclipse.jetty.http2.HTTP2FlowControl; -import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.Session; -import org.eclipse.jetty.http2.generator.Generator; -import org.eclipse.jetty.http2.parser.Parser; -import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.io.SelectChannelEndPoint; import org.eclipse.jetty.io.SelectorManager; +import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.eclipse.jetty.util.thread.Scheduler; @@ -80,6 +79,11 @@ public class HTTP2Client extends ContainerLifeCycle } public void connect(InetSocketAddress address, Session.Listener listener, Promise<Session> promise) + { + connect(null, address, listener, promise); + } + + public void connect(SslContextFactory sslContextFactory, InetSocketAddress address, Session.Listener listener, Promise<Session> promise) { try { @@ -87,7 +91,17 @@ public class HTTP2Client extends ContainerLifeCycle channel.socket().setTcpNoDelay(true); channel.configureBlocking(false); channel.connect(address); - selector.connect(channel, new Context(listener, promise)); + + Map<String, Object> context = new HashMap<>(); + context.put(HTTP2ClientConnectionFactory.CLIENT_CONTEXT_KEY, this); + context.put(HTTP2ClientConnectionFactory.SESSION_LISTENER_CONTEXT_KEY, listener); + context.put(HTTP2ClientConnectionFactory.SESSION_PROMISE_CONTEXT_KEY, promise); + if (sslContextFactory != null) + context.put(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY, sslContextFactory); + context.put(SslClientConnectionFactory.SSL_PEER_HOST_CONTEXT_KEY, address.getHostString()); + context.put(SslClientConnectionFactory.SSL_PEER_PORT_CONTEXT_KEY, address.getPort()); + + selector.connect(channel, context); } catch (Throwable x) { @@ -112,6 +126,16 @@ public class HTTP2Client extends ContainerLifeCycle this.idleTimeout = idleTimeout; } + public boolean addSession(ISession session) + { + return sessions.offer(session); + } + + public boolean removeSession(ISession session) + { + return sessions.remove(session); + } + private class ClientSelectorManager extends SelectorManager { private ClientSelectorManager(Executor executor, Scheduler scheduler) @@ -128,71 +152,22 @@ public class HTTP2Client extends ContainerLifeCycle @Override public Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException { - Context context = (Context)attachment; - Generator generator = new Generator(byteBufferPool, 4096); - HTTP2Session session = new HTTP2ClientSession(getScheduler(), endpoint, generator, context.listener, new HTTP2FlowControl(65535)); - Parser parser = new Parser(byteBufferPool, session, 4096, 8192); - return new HTTP2ClientConnection(byteBufferPool, getExecutor(), endpoint, parser, session, 8192, context.promise); - } - } + @SuppressWarnings("unchecked") + Map<String, Object> context = (Map<String, Object>)attachment; + context.put(HTTP2ClientConnectionFactory.BYTE_BUFFER_POOL_CONTEXT_KEY, byteBufferPool); + context.put(HTTP2ClientConnectionFactory.EXECUTOR_CONTEXT_KEY, getExecutor()); + context.put(HTTP2ClientConnectionFactory.SCHEDULER_CONTEXT_KEY, getScheduler()); - private class HTTP2ClientConnection extends HTTP2Connection implements Callback - { - private final Promise<Session> promise; + ClientConnectionFactory factory = new HTTP2ClientConnectionFactory(); - public HTTP2ClientConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise) - { - super(byteBufferPool, executor, endpoint, parser, session, bufferSize); - this.promise = promise; - } + SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY); + if (sslContextFactory != null) + { + ALPNClientConnectionFactory alpn = new ALPNClientConnectionFactory(getExecutor(), factory, "h2-14"); + factory = new SslClientConnectionFactory(sslContextFactory, byteBufferPool, getExecutor(), alpn); + } - @Override - public void onOpen() - { - super.onOpen(); - getEndPoint().write(this, ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES)); - } - - @Override - public void onClose() - { - super.onClose(); - sessions.remove(getSession()); - } - - @Override - protected boolean onReadTimeout() - { - if (LOG.isDebugEnabled()) - LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); - getSession().close(ErrorCodes.NO_ERROR, "idle_timeout", closeCallback); - return false; - } - - @Override - public void succeeded() - { - sessions.offer(getSession()); - promise.succeeded(getSession()); - } - - @Override - public void failed(Throwable x) - { - close(); - promise.failed(x); - } - } - - private class Context - { - private final Session.Listener listener; - private final Promise<Session> promise; - - private Context(Session.Listener listener, Promise<Session> promise) - { - this.listener = listener; - this.promise = promise; + return factory.newConnection(endpoint, context); } } } diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java new file mode 100644 index 00000000000..f03df621109 --- /dev/null +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -0,0 +1,118 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.concurrent.Executor; + +import org.eclipse.jetty.http2.ErrorCodes; +import org.eclipse.jetty.http2.HTTP2Connection; +import org.eclipse.jetty.http2.HTTP2FlowControl; +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.ISession; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.http2.parser.PrefaceParser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.ClientConnectionFactory; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.thread.Scheduler; + +public class HTTP2ClientConnectionFactory implements ClientConnectionFactory +{ + public static final String CLIENT_CONTEXT_KEY = "http2.client"; + public static final String BYTE_BUFFER_POOL_CONTEXT_KEY = "http2.client.byteBufferPool"; + public static final String EXECUTOR_CONTEXT_KEY = "http2.client.executor"; + public static final String SCHEDULER_CONTEXT_KEY = "http2.client.scheduler"; + public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener"; + public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise"; + + @Override + public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException + { + HTTP2Client client = (HTTP2Client)context.get(CLIENT_CONTEXT_KEY); + ByteBufferPool byteBufferPool = (ByteBufferPool)context.get(BYTE_BUFFER_POOL_CONTEXT_KEY); + Executor executor = (Executor)context.get(EXECUTOR_CONTEXT_KEY); + Scheduler scheduler = (Scheduler)context.get(SCHEDULER_CONTEXT_KEY); + Session.Listener listener = (Session.Listener)context.get(SESSION_LISTENER_CONTEXT_KEY); + @SuppressWarnings("unchecked") + Promise<Session> promise = (Promise<Session>)context.get(SESSION_PROMISE_CONTEXT_KEY); + + Generator generator = new Generator(byteBufferPool, 4096); + HTTP2Session session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, new HTTP2FlowControl(65535)); + Parser parser = new Parser(byteBufferPool, session, 4096, 8192); + return new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, 8192, promise); + } + + private class HTTP2ClientConnection extends HTTP2Connection implements Callback + { + private final HTTP2Client client; + private final Promise<Session> promise; + + public HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise) + { + super(byteBufferPool, executor, endpoint, parser, session, bufferSize); + this.client = client; + this.promise = promise; + } + + @Override + public void onOpen() + { + super.onOpen(); + getEndPoint().write(this, ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES)); + } + + @Override + public void onClose() + { + super.onClose(); + client.removeSession(getSession()); + } + + @Override + protected boolean onReadTimeout() + { + if (LOG.isDebugEnabled()) + LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); + getSession().close(ErrorCodes.NO_ERROR, "idle_timeout", closeCallback); + return false; + } + + @Override + public void succeeded() + { + client.addSession(getSession()); + promise.succeeded(getSession()); + } + + @Override + public void failed(Throwable x) + { + close(); + promise.failed(x); + } + } +} diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java new file mode 100644 index 00000000000..f5cb3136bd4 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java @@ -0,0 +1,71 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.net.InetSocketAddress; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.Jetty; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +public class Client +{ + public static void main(String[] args) throws Exception + { + HTTP2Client client = new HTTP2Client(); + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setIncludeProtocols("TLSv1.2", "TLSv1.1", "TLSv1"); + client.addBean(sslContextFactory); + client.start(); + + FuturePromise<Session> sessionPromise = new FuturePromise<>(); + client.connect(sslContextFactory, new InetSocketAddress("testsite.webtide.com", 443), new ServerSessionListener.Adapter(), sessionPromise); + Session session = sessionPromise.get(5, TimeUnit.SECONDS); + + HttpFields requestFields = new HttpFields(); + requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION); + MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://testsite.webtide.com/"), HttpVersion.HTTP_2, requestFields); + HeadersFrame headersFrame = new HeadersFrame(0, metaData, null, true); + final CountDownLatch latch = new CountDownLatch(1); + session.newStream(headersFrame, new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + System.err.println(frame.getMetaData()); + latch.countDown(); + } + }); + + latch.await(5, TimeUnit.SECONDS); + + client.stop(); + } +} diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java index ce3be14a7b6..db3f1a69a0b 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.io.ssl; import java.io.IOException; import java.util.Map; import java.util.concurrent.Executor; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.ByteBufferPool; @@ -31,6 +30,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; public class SslClientConnectionFactory implements ClientConnectionFactory { + public static final String SSL_CONTEXT_FACTORY_CONTEXT_KEY = "ssl.context.factory"; public static final String SSL_PEER_HOST_CONTEXT_KEY = "ssl.peer.host"; public static final String SSL_PEER_PORT_CONTEXT_KEY = "ssl.peer.port"; public static final String SSL_ENGINE_CONTEXT_KEY = "ssl.engine"; From 38501a9e978335c63ed52555f8b6d2d8e4f138f8 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Fri, 1 Aug 2014 14:34:21 -0700 Subject: [PATCH 179/269] On alias resolution in PathResource, ignore NoSuchFileException (its a valid and common path for 404 requested resources) --- .../java/org/eclipse/jetty/util/resource/PathResource.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java index 0a5812d0a0f..da48349e719 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java @@ -32,6 +32,7 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.FileTime; @@ -71,6 +72,10 @@ public class PathResource extends Resource return realUri; } } + catch (NoSuchFileException e) + { + // Ignore + } catch (IOException e) { // TODO: reevaluate severity level From 7406a280b30ccf8b00040982a4e7e661e546c326 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Fri, 1 Aug 2014 14:50:54 -0700 Subject: [PATCH 180/269] Adding some extra proxy tests around spaces in query parameters --- .../eclipse/jetty/proxy/ProxyServletTest.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java index 40d99b06e66..90320a3b957 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java @@ -672,6 +672,48 @@ public class ProxyServletTest Assert.assertEquals(200, response.getStatus()); Assert.assertTrue(response.getHeaders().containsKey(PROXIED_HEADER)); } + + @Test + public void testTransparentProxyWithQueryWithSpaces() throws Exception + { + final String target = "/test"; + final String query = "a=1&b=2&c=1234%205678&d=hello+world"; + prepareServer(new HttpServlet() + { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + if (req.getHeader("Via") != null) + resp.addHeader(PROXIED_HEADER, "true"); + + if (target.equals(req.getRequestURI())) + { + if (query.equals(req.getQueryString())) + { + resp.setStatus(200); + return; + } + } + resp.setStatus(404); + } + }); + + String proxyTo = "http://localhost:" + serverConnector.getLocalPort(); + String prefix = "/proxy"; + proxyServlet = new ProxyServlet.Transparent(); + Map<String, String> params = new HashMap<>(); + params.put("proxyTo", proxyTo); + params.put("prefix", prefix); + prepareProxy(params); + + // Make the request to the proxy, it should transparently forward to the server + ContentResponse response = client.newRequest("localhost", proxyConnector.getLocalPort()) + .path(prefix + target + "?" + query) + .timeout(5, TimeUnit.SECONDS) + .send(); + Assert.assertEquals(200, response.getStatus()); + Assert.assertTrue(response.getHeaders().containsKey(PROXIED_HEADER)); + } @Test public void testTransparentProxyWithoutPrefix() throws Exception From 87c4c5efd337b6609db2171bf81a5767285e5329 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 22:29:29 +0200 Subject: [PATCH 181/269] Updated to point to webtide.com, now HTTP/2 enabled. --- .../src/test/java/org/eclipse/jetty/http2/client/Client.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java index f5cb3136bd4..0fd6ed9f6a2 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java @@ -46,12 +46,12 @@ public class Client client.start(); FuturePromise<Session> sessionPromise = new FuturePromise<>(); - client.connect(sslContextFactory, new InetSocketAddress("testsite.webtide.com", 443), new ServerSessionListener.Adapter(), sessionPromise); + client.connect(sslContextFactory, new InetSocketAddress("webtide.com", 443), new ServerSessionListener.Adapter(), sessionPromise); Session session = sessionPromise.get(5, TimeUnit.SECONDS); HttpFields requestFields = new HttpFields(); requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION); - MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://testsite.webtide.com/"), HttpVersion.HTTP_2, requestFields); + MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://webtide.com/"), HttpVersion.HTTP_2, requestFields); HeadersFrame headersFrame = new HeadersFrame(0, metaData, null, true); final CountDownLatch latch = new CountDownLatch(1); session.newStream(headersFrame, new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() From 9a85f4cea627cbf1420d0a3c32e0b846a4901ae4 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 1 Aug 2014 23:56:22 +0200 Subject: [PATCH 182/269] Fixed typo. --- .../jetty-alpn-server/src/main/config/etc/protonego-alpn.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml index 5d2ac7ae2c2..3c1ed6daacc 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml +++ b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml @@ -12,7 +12,7 @@ <Set name="defaultProtocol">http/1.1</Set> - <!-- Enables NPN debugging on System.err --> + <!-- Enables ALPN debugging on System.err --> <!--<Set class="org.eclipse.jetty.alpn.ALPN" name="debug" type="boolean">true</Set>--> </Configure> From dcc8bfcd10d19176ee9d06dbd6cea1c1383e7e74 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Sat, 2 Aug 2014 00:01:56 +0200 Subject: [PATCH 183/269] Fixed a reentrancy issue that caused a stack overflow. The case was that shutdown was called, ShutdownFlusherEntry called flusher.close(), which called super.close(), which called onCompleteFailure(), which looped over the active items to fail them, calling again ShutdownFlusherEntry, which called again flusher.close(), etc. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 0b98d5c2b7d..dfdc4adc20f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -588,11 +588,13 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final ByteBufferPool.Lease lease = new ByteBufferPool.Lease(generator.getByteBufferPool()); private final int maxGather; private final List<FlusherEntry> active; + private final Queue<FlusherEntry> complete; private Flusher(int maxGather) { this.maxGather = maxGather; this.active = new ArrayList<>(maxGather); + this.complete = new ArrayDeque<>(maxGather); } private void append(FlusherEntry entry) @@ -731,12 +733,19 @@ public abstract class HTTP2Session implements ISession, Parser.Listener public void succeeded() { lease.recycle(); + + // Transfer active items to avoid reentrancy. for (int i = 0; i < active.size(); ++i) + complete.add(active.get(i)); + active.clear(); + + // Drain the queue one by one to avoid reentrancy. + while (!complete.isEmpty()) { - FlusherEntry entry = active.get(i); + FlusherEntry entry = complete.poll(); entry.succeeded(); } - active.clear(); + super.succeeded(); } @@ -749,31 +758,40 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override protected void onCompleteFailure(Throwable x) { - LOG.debug(x); + if (LOG.isDebugEnabled()) + LOG.debug(x); + lease.recycle(); + + // Transfer active items to avoid reentrancy. for (int i = 0; i < active.size(); ++i) + complete.add(active.get(i)); + active.clear(); + + // Drain the queue one by one to avoid reentrancy. + while (!complete.isEmpty()) { - FlusherEntry entry = active.get(i); + FlusherEntry entry = complete.poll(); entry.failed(x); } - active.clear(); } public void close() { + super.close(); + Queue<FlusherEntry> queued; synchronized (queue) { - super.close(); queued = new ArrayDeque<>(queue); + queue.clear(); } if (LOG.isDebugEnabled()) LOG.debug("Closing, queued={}", queued.size()); - for (FlusherEntry item: queued) + for (FlusherEntry item : queued) closed(item); - } protected void closed(FlusherEntry item) From 1873b306b37616252b989bca44b36209ab40a08a Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Sat, 2 Aug 2014 12:56:12 +1000 Subject: [PATCH 184/269] Improved hpack encoder handling of custom fields --- .../jetty/http2/hpack/HpackEncoder.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 158cc4e572c..fec8dea44f1 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -196,6 +196,9 @@ public class HpackEncoder { // Must be a new entry, so we will have to send literally. + // Look for a name Index + Entry name_entry = _context.get(field.getName()); + HttpHeader header = field.getHeader(); final boolean never_index; final boolean huffman; @@ -203,12 +206,28 @@ public class HpackEncoder final int name_bits; if (header==null) { - // unknown header. - never_index=false; - huffman=true; - indexed=true; - name_bits = 6; - buffer.put((byte)0x40); + // has the custom header name been seen before? + if (name_entry==null) + { + // unknown name and value, so let's index this just in case it is + // the first time we have seen a custom name or a custom field. + // unless the name is changing, this is worthwhile + indexed=true; + never_index=false; + huffman=true; + name_bits = 6; + buffer.put((byte)0x40); + } + else + { + // known custom name, but unknown value. + // This is probably a custom field with changing value, so don't index now. + indexed=false; + never_index=false; + huffman=true; + name_bits = 4; + buffer.put((byte)0x00); + } } else if (__DO_NOT_INDEX.contains(header)) { @@ -238,8 +257,6 @@ public class HpackEncoder buffer.put((byte)0x40); } - // Look for a name Index - Entry name_entry = _context.get(field.getName()); if (p>=0) { @@ -253,6 +270,7 @@ public class HpackEncoder NBitInteger.encode(buffer,name_bits,_context.index(name_entry)); else { + // leave name index bits as 0 // Encode the name always with lowercase huffman buffer.put((byte)0x80); NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(field.getName())); From aaa2e5c6c1d6d34f8068dc9a056a6b446fd05603 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Sat, 2 Aug 2014 12:58:24 +1000 Subject: [PATCH 185/269] refined PathResource alias handling --- .../quickstart/QuickStartConfiguration.java | 2 +- .../handler/AllowSymLinkAliasChecker.java | 67 +++++++++---------- .../jetty/server/handler/ContextHandler.java | 2 +- .../jetty/server/handler/ResourceHandler.java | 2 +- .../ContextHandlerGetResourceTest.java | 5 +- .../jetty/util/resource/PathResource.java | 51 +++++++++----- .../eclipse/jetty/util/resource/Resource.java | 6 ++ .../util/resource/FileSystemResourceTest.java | 44 +++++++++++- .../jetty/webapp/WebInfConfiguration.java | 2 +- 9 files changed, 124 insertions(+), 57 deletions(-) diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java index 85f95dcb6ab..88552d660a7 100644 --- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java +++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java @@ -57,7 +57,7 @@ public class QuickStartConfiguration extends WebInfConfiguration Resource webApp = context.newResource(war); // Accept aliases for WAR files - if (webApp.getAlias() != null) + if (webApp.isAlias()) { LOG.debug(webApp + " anti-aliased to " + webApp.getAlias()); webApp = context.newResource(webApp.getAlias()); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java index 427c5b05929..5a402ec7d98 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java @@ -26,6 +26,7 @@ import java.nio.file.Path; import org.eclipse.jetty.server.handler.ContextHandler.AliasCheck; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.PathResource; import org.eclipse.jetty.util.resource.Resource; @@ -41,56 +42,52 @@ public class AllowSymLinkAliasChecker implements AliasCheck private static final Logger LOG = Log.getLogger(AllowSymLinkAliasChecker.class); @Override - public boolean check(String path, Resource resource) + public boolean check(String uri, Resource resource) { + // Only support PathResource alias checking + if (!(resource instanceof PathResource)) + return false; + + PathResource pathResource = (PathResource)resource; + try { - File file =resource.getFile(); - if (file==null) - return false; + Path path = pathResource.getPath(); - // If the file exists - if (file.exists()) + // is the file itself a symlink? + if (Files.isSymbolicLink(path) && Files.isSameFile(path,pathResource.getAliasPath())) { - // we can use the real path method to check the symlinks resolve to the alias - URI real = file.toPath().toRealPath().toUri(); - if (real.equals(resource.getAlias())) + if (LOG.isDebugEnabled()) + LOG.debug("Allow symlink {} --> {}",resource,pathResource.getAliasPath()); + return true; + } + + // No, so let's check each element ourselves + Path d = path.getRoot(); + for (Path e:path) + { + d=d.resolve(e); + + while (Files.exists(d) && Files.isSymbolicLink(d)) { - if (LOG.isDebugEnabled()) - LOG.debug("Allow symlink {} --> {}",resource,real); - return true; + Path link=Files.readSymbolicLink(d); + if (!link.isAbsolute()) + link=d.resolve(link); + d=link; } } - else + if (pathResource.getAliasPath().equals(d)) { - // file does not exists, so we have to walk the path and links ourselves. - Path p = file.toPath().toAbsolutePath(); - File d = p.getRoot().toFile(); - for (Path e:p) - { - d=new File(d,e.toString()); - - while (d.exists() && Files.isSymbolicLink(d.toPath())) - { - Path link=Files.readSymbolicLink(d.toPath()); - if (!link.isAbsolute()) - link=link.resolve(d.toPath()); - d=link.toFile().getAbsoluteFile().getCanonicalFile(); - } - } - if (resource.getAlias().equals(d.toURI())) - { - if (LOG.isDebugEnabled()) - LOG.debug("Allow symlink {} --> {}",resource,d); - return true; - } + if (LOG.isDebugEnabled()) + LOG.debug("Allow path symlink {} --> {}",resource,d); + return true; } } catch(Exception e) { - e.printStackTrace(); LOG.ignore(e); } + return false; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 8208110f8de..9dc9794fa40 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -1668,7 +1668,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu public boolean checkAlias(String path, Resource resource) { // Is the resource aliased? - if (resource.getAlias() != null) + if (resource.isAlias()) { if (LOG.isDebugEnabled()) LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias()); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java index 80375a47f50..2f95f6cc025 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java @@ -315,7 +315,7 @@ public class ResourceHandler extends HandlerWrapper { path=URIUtil.canonicalPath(path); Resource r = base.addPath(path); - if (r!=null && r.getAlias()!=null && !_context.checkAlias(path, r)) + if (r!=null && r.isAlias() && !_context.checkAlias(path, r)) return null; return r; } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java index 1f5cddd74e1..aace3e77797 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java @@ -33,6 +33,7 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.util.resource.Resource; import org.junit.AfterClass; +import org.junit.Assert; import org.junit.Assume; import org.junit.BeforeClass; import org.junit.Test; @@ -352,8 +353,8 @@ public class ContextHandlerGetResourceTest @Test public void testSymlinkKnown() throws Exception { - if (!OS.IS_UNIX) - return; + Assume.assumeTrue(OS.IS_UNIX); + try { allowSymlinks.set(true); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java index da48349e719..c7da550de8a 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java @@ -50,36 +50,41 @@ import org.eclipse.jetty.util.log.Logger; public class PathResource extends Resource { private static final Logger LOG = Log.getLogger(PathResource.class); - private final static LinkOption NO_FOLLOW_OPTIONS[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; + private final static LinkOption NO_FOLLOW_LINKS[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; + private final static LinkOption FOLLOW_LINKS[] = new LinkOption[] {}; private final Path path; - private final URI alias; + private final Path alias; private final URI uri; - private static final URI toAliasUri(final Path path) + private static final Path checkAliasPath(final Path path) { Path abs = path; if (!abs.isAbsolute()) { abs = path.toAbsolutePath(); } - URI providedUri = abs.toUri(); + try { - URI realUri = abs.toRealPath().toUri(); - if (!providedUri.equals(realUri)) + if (Files.isSymbolicLink(path)) + return Files.readSymbolicLink(path); + if (Files.exists(path)) { - return realUri; + Path real = abs.toRealPath(FOLLOW_LINKS); + if (!abs.equals(real)) + return real; } } catch (NoSuchFileException e) { // Ignore } - catch (IOException e) + catch (Exception e) { // TODO: reevaluate severity level LOG.warn("bad alias ({}) for {}", e.getClass().getName(), e.getMessage()); + return abs; } return null; } @@ -93,7 +98,7 @@ public class PathResource extends Resource { this.path = path.toAbsolutePath(); this.uri = this.path.toUri(); - this.alias = toAliasUri(path); + this.alias = checkAliasPath(path); } public PathResource(URI uri) throws IOException @@ -129,7 +134,7 @@ public class PathResource extends Resource this.path = path.toAbsolutePath(); this.uri = path.toUri(); - this.alias = toAliasUri(path); + this.alias = checkAliasPath(path); } public PathResource(URL url) throws IOException, URISyntaxException @@ -211,7 +216,7 @@ public class PathResource extends Resource @Override public boolean exists() { - return Files.exists(path,NO_FOLLOW_OPTIONS); + return Files.exists(path,NO_FOLLOW_LINKS); } @Override @@ -220,6 +225,11 @@ public class PathResource extends Resource return path.toFile(); } + public Path getPath() throws IOException + { + return path; + } + @Override public InputStream getInputStream() throws IOException { @@ -276,7 +286,7 @@ public class PathResource extends Resource @Override public boolean isDirectory() { - return Files.isDirectory(path,NO_FOLLOW_OPTIONS); + return Files.isDirectory(path,NO_FOLLOW_LINKS); } @Override @@ -284,7 +294,7 @@ public class PathResource extends Resource { try { - FileTime ft = Files.getLastModifiedTime(path,NO_FOLLOW_OPTIONS); + FileTime ft = Files.getLastModifiedTime(path,NO_FOLLOW_LINKS); return ft.toMillis(); } catch (IOException e) @@ -309,10 +319,21 @@ public class PathResource extends Resource } @Override - public URI getAlias() + public boolean isAlias() + { + return this.alias!=null; + } + + public Path getAliasPath() { return this.alias; } + + @Override + public URI getAlias() + { + return this.alias==null?null:this.alias.toUri(); + } @Override public String[] list() @@ -354,7 +375,7 @@ public class PathResource extends Resource try { Path result = Files.move(path,destRes.path); - return Files.exists(result,NO_FOLLOW_OPTIONS); + return Files.exists(result,NO_FOLLOW_LINKS); } catch (IOException e) { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java index 47624441768..cf62cf3ed3c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java @@ -475,6 +475,12 @@ public abstract class Resource implements ResourceFactory, Closeable { _associate=o; } + + /* ------------------------------------------------------------ */ + public boolean isAlias() + { + return getAlias()!=null; + } /* ------------------------------------------------------------ */ /** diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java index 5b65894a3d1..ec4cc2b8f68 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java @@ -134,7 +134,7 @@ public class FileSystemResourceTest public boolean matches(Object item) { final Resource res = (Resource)item; - return res.getAlias() == null; + return !res.isAlias(); } @Override @@ -497,6 +497,48 @@ public class FileSystemResourceTest assertThat("file.alias", newResource(resBar.getFile()), isAliasFor(resFoo)); } } + + @Test + public void testNonExistantSymlink() throws Exception + { + File dir = testdir.getDir(); + + Path foo = new File(dir, "foo").toPath(); + Path bar = new File(dir, "bar").toPath(); + + try + { + Files.createSymbolicLink(bar,foo); + } + catch (UnsupportedOperationException | FileSystemException e) + { + // if unable to create symlink, no point testing the rest + // this is the path that Microsoft Windows takes. + assumeNoException(e); + } + + try (Resource base = newResource(testdir.getDir())) + { + // FileResource does not pass this test! + assumeFalse(base instanceof FileResource); + + Resource resFoo = base.addPath("foo"); + Resource resBar = base.addPath("bar"); + + assertThat("resFoo.uri", resFoo.getURI(), is(foo.toUri())); + + // Access to the same resource, but via a symlink means that they are not equivalent + assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false)); + + assertThat("resource.alias", resFoo, hasNoAlias()); + assertThat("resource.uri.alias", newResource(resFoo.getURI()), hasNoAlias()); + assertThat("resource.file.alias", newResource(resFoo.getFile()), hasNoAlias()); + + assertThat("alias", resBar, isAliasFor(resFoo)); + assertThat("uri.alias", newResource(resBar.getURI()), isAliasFor(resFoo)); + assertThat("file.alias", newResource(resBar.getFile()), isAliasFor(resFoo)); + } + } @Test diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 1e4096c19cb..39821a55773 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -402,7 +402,7 @@ public class WebInfConfiguration extends AbstractConfiguration throw new IllegalStateException("No resourceBase or war set for context"); // Accept aliases for WAR files - if (web_app.getAlias() != null) + if (web_app.isAlias()) { LOG.debug(web_app + " anti-aliased to " + web_app.getAlias()); web_app = context.newResource(web_app.getAlias()); From cd59d0085ed5f3a224984795a3daf353fd8d1b0c Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Sat, 2 Aug 2014 15:40:15 +1000 Subject: [PATCH 186/269] improve known header handling in hpack encoding --- .../org/eclipse/jetty/http/HttpHeader.java | 14 ++- .../jetty/http2/hpack/HpackContext.java | 19 +++- .../jetty/http2/hpack/HpackEncoder.java | 93 ++++++++++--------- .../jetty/http2/hpack/HpackPerfTest.java | 16 ++-- 4 files changed, 87 insertions(+), 55 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java index ab0ddcf3b0f..1a89b8891a8 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java @@ -111,16 +111,26 @@ public enum HttpHeader X_POWERED_BY("X-Powered-By"), + /* ------------------------------------------------------------ */ + /** HTTP2 Fields. + */ + C_METHOD(":method"), + C_SCHEME(":scheme"), + C_AUTHORITY(":authority"), + C_PATH(":path"), + C_STATUS(":status"), + UNKNOWN("::UNKNOWN::"); /* ------------------------------------------------------------ */ - public final static Trie<HttpHeader> CACHE= new ArrayTrie<>(512); + public final static Trie<HttpHeader> CACHE= new ArrayTrie<>(520); static { for (HttpHeader header : HttpHeader.values()) if (header!=UNKNOWN) - CACHE.put(header.toString(),header); + if (!CACHE.put(header.toString(),header)) + throw new IllegalStateException(); } private final String _string; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 659f950ffae..f058885a3b6 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -25,8 +25,10 @@ import java.util.Map; import java.util.Set; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.StringUtil; @@ -106,7 +108,7 @@ public class HpackContext private static final Map<HttpField,Entry> __staticFieldMap = new HashMap<>(); private static final Trie<Entry> __staticNameMap = new ArrayTernaryTrie<>(true,512); - + private static final Entry[] __headerEntryTable = new Entry[HttpHeader.UNKNOWN.ordinal()]; private static final StaticEntry[] __staticTable=new StaticEntry[STATIC_TABLE.length]; static { @@ -158,6 +160,13 @@ public class HpackContext throw new IllegalStateException("name trie too small"); } } + + for (HttpHeader h : HttpHeader.values()) + { + Entry entry = __staticNameMap.get(h.asString()); + if (entry!=null) + __headerEntryTable[h.ordinal()]=entry; + } } @@ -215,6 +224,14 @@ public class HpackContext return null; } + public Entry get(HttpHeader header) + { + Entry e = __headerEntryTable[header.ordinal()]; + if (e==null) + return get(header.asString()); + return e; + } + public Entry add(HttpField field) { int slot=_headerTable.getNextSlotUnsafe(); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index fec8dea44f1..3832ffa1cca 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -50,6 +50,7 @@ public class HpackEncoder private final static EnumSet<HttpHeader> __DO_NOT_INDEX = EnumSet.of( + // TODO ??? HttpHeader.C_PATH, HttpHeader.CONTENT_MD5, HttpHeader.CONTENT_RANGE, HttpHeader.ETAG, @@ -139,10 +140,10 @@ public class HpackEncoder // TODO optimise these to avoid HttpField creation String scheme=request.getURI().getScheme(); - encode(buffer,new HttpField(":scheme",scheme==null?HttpScheme.HTTP.asString():scheme)); - encode(buffer,new HttpField(":method",request.getMethod())); - encode(buffer,new HttpField(":authority",request.getURI().getAuthority())); - encode(buffer,new HttpField(":path",request.getURI().getPathQuery())); + encode(buffer,new HttpField(HttpHeader.C_SCHEME,scheme==null?HttpScheme.HTTP.asString():scheme)); + encode(buffer,new HttpField(HttpHeader.C_METHOD,request.getMethod())); + encode(buffer,new HttpField(HttpHeader.C_AUTHORITY,request.getURI().getAuthority())); + encode(buffer,new HttpField(HttpHeader.C_PATH,request.getURI().getPathQuery())); } else if (metadata.isResponse()) @@ -151,7 +152,7 @@ public class HpackEncoder int code=response.getStatus(); HttpField status = code<__status.length?__status[code]:null; if (status==null) - status=new HttpField(":status",Integer.toString(code)); + status=new HttpField(HttpHeader.C_STATUS,Integer.toString(code)); encode(buffer,status); } @@ -188,7 +189,7 @@ public class HpackEncoder { int index=_context.index(entry); if (p>=0) - encoding="Indexed"+index; + encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index)); buffer.put((byte)0x80); NBitInteger.encode(buffer,7,index); } @@ -196,18 +197,18 @@ public class HpackEncoder { // Must be a new entry, so we will have to send literally. - // Look for a name Index - Entry name_entry = _context.get(field.getName()); - - HttpHeader header = field.getHeader(); + final Entry name; + final boolean indexed; final boolean never_index; final boolean huffman; - final boolean indexed; - final int name_bits; + final int bits; + + HttpHeader header = field.getHeader(); if (header==null) { + name = _context.get(field.getName()); // has the custom header name been seen before? - if (name_entry==null) + if (name==null) { // unknown name and value, so let's index this just in case it is // the first time we have seen a custom name or a custom field. @@ -215,7 +216,7 @@ public class HpackEncoder indexed=true; never_index=false; huffman=true; - name_bits = 6; + bits = 6; buffer.put((byte)0x40); } else @@ -225,49 +226,53 @@ public class HpackEncoder indexed=false; never_index=false; huffman=true; - name_bits = 4; + bits = 4; buffer.put((byte)0x00); } } - else if (__DO_NOT_INDEX.contains(header)) + else { - // Non indexed field - indexed=false; - never_index=__NEVER_INDEX.contains(header); - huffman=!__DO_NOT_HUFFMAN.contains(header); - name_bits = 4; - buffer.put(never_index?(byte)0x10:(byte)0x00); - } - else if (header==HttpHeader.CONTENT_LENGTH && field.getValue().length()>1) - { - // Non indexed content length for non zero value - indexed=false; - never_index=false; - huffman=true; - name_bits = 4; - buffer.put((byte)0x00); - } - else - { - // indexed - indexed=true; - never_index=false; - huffman=!__DO_NOT_HUFFMAN.contains(header); - name_bits = 6; - buffer.put((byte)0x40); - } + name = _context.get(header); + if (__DO_NOT_INDEX.contains(header)) + { + // Non indexed field + indexed=false; + never_index=__NEVER_INDEX.contains(header); + huffman=!__DO_NOT_HUFFMAN.contains(header); + bits = 4; + buffer.put(never_index?(byte)0x10:(byte)0x00); + } + else if (header==HttpHeader.CONTENT_LENGTH && field.getValue().length()>1) + { + // Non indexed content length for non zero value + indexed=false; + never_index=false; + huffman=true; + bits = 4; + buffer.put((byte)0x00); + } + else + { + // indexed + indexed=true; + never_index=false; + huffman=!__DO_NOT_HUFFMAN.contains(header); + bits = 6; + buffer.put((byte)0x40); + } + } if (p>=0) { encoding="Lit"+ - ((name_entry==null)?"HuffN":"IdxN")+ + ((name==null)?"HuffN":("IdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(bits,_context.index(name)))))+ (huffman?"HuffV":"LitV")+ (indexed?"Idx":(never_index?"!!Idx":"!Idx")); } - if (name_entry!=null) - NBitInteger.encode(buffer,name_bits,_context.index(name_entry)); + if (name!=null) + NBitInteger.encode(buffer,bits,_context.index(name)); else { // leave name index bits as 0 diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java index f927ebfe9a2..79d93ce8005 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java @@ -52,17 +52,17 @@ public class HpackPerfTest @After public void after() { - System.err.printf("headertable=%d unencoded=%d encoded=%d p=%d%%%n",_maxHeaderTableSize,_unencodedSize,_encodedSize,(100*_encodedSize+49)/_unencodedSize); + System.err.printf("headertable=%d unencoded=%d encoded=%d p=%3.1f%%%n",_maxHeaderTableSize,_unencodedSize,_encodedSize,100.0*_encodedSize/_unencodedSize); } @Test public void simpleTest() throws Exception { - runStories(_maxHeaderTableSize,new HpackEncoder(_maxHeaderTableSize,_maxHeaderTableSize)); + runStories(_maxHeaderTableSize); } - private void runStories(int maxHeaderTableSize, HpackEncoder encoder) throws Exception + private void runStories(int maxHeaderTableSize) throws Exception { // Find files File data = MavenTestingUtils.getTestResourceDir("data"); @@ -84,25 +84,25 @@ public class HpackPerfTest ByteBuffer buffer = BufferUtil.allocate(256*1024); // Encode all the requests - encodeStories(buffer,stories,"request",encoder); + encodeStories(buffer,stories,"request"); // clear table BufferUtil.clearToFill(buffer); - encoder.encodeMaxHeaderTableSize(buffer,0); - encoder.encodeMaxHeaderTableSize(buffer,maxHeaderTableSize); BufferUtil.flipToFlush(buffer,0); // Encode all the responses - encodeStories(buffer,stories,"response",encoder); + encodeStories(buffer,stories,"response"); } - private void encodeStories(ByteBuffer buffer,Map<String,Object>[] stories, String type, HpackEncoder encoder) throws Exception + private void encodeStories(ByteBuffer buffer,Map<String,Object>[] stories, String type) throws Exception { for (Map<String,Object> story : stories) { if (type.equals(story.get("context"))) { + HpackEncoder encoder = new HpackEncoder(_maxHeaderTableSize,_maxHeaderTableSize); + // System.err.println(story); Object[] cases = (Object[])story.get("cases"); for (Object c : cases) From 1fb07644a18cd6008f5d8f61f4423e11968a0ef1 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Sat, 2 Aug 2014 16:37:43 +1000 Subject: [PATCH 187/269] Use HttpHeader enum for :path and similar h2 fields --- .../org/eclipse/jetty/http/HttpField.java | 5 +- .../jetty/http2/hpack/AuthorityHttpField.java | 3 +- .../jetty/http2/hpack/HpackDecoder.java | 76 ++++++++++--------- .../jetty/http2/hpack/HpackEncoder.java | 13 ++-- .../jetty/http2/hpack/MetaDataBuilder.java | 28 ++++--- .../jetty/http2/hpack/HpackDecoderTest.java | 8 +- 6 files changed, 72 insertions(+), 61 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index 3ac0f333e74..74db3037482 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -382,8 +382,9 @@ public class HttpField int len = _name.length(); for (int i = 0; i < len; i++) { - char c = Character.toUpperCase(_name.charAt(i)); - hash = 31 * hash + c; + // simple case insensitive hash + char c = _name.charAt(i); + hash = 15 * hash + 0x0F&c; } return hash; } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java index a0672d122a4..8c2ca4847d2 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.hpack; import org.eclipse.jetty.http.HostPortHttpField; +import org.eclipse.jetty.http.HttpHeader; /* ------------------------------------------------------------ */ @@ -31,7 +32,7 @@ public class AuthorityHttpField extends HostPortHttpField public AuthorityHttpField(String authority) { - super(null,AUTHORITY,authority); + super(HttpHeader.C_AUTHORITY,AUTHORITY,authority); } @Override diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index f72ae862e6c..cb32ccff76a 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -27,7 +27,6 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.TypeUtil; @@ -190,47 +189,54 @@ public class HpackDecoder // Make the new field HttpField field; - switch(name) + if (header==null) { - case ":method": - HttpMethod method=HttpMethod.CACHE.get(value); - if (method!=null) - field = new StaticValueHttpField(header,name,method.asString(),method); - else - field = new AuthorityHttpField(value); - break; + field = new HttpField(null,name,value); + } + else + { + switch(header) + { + case C_METHOD: + HttpMethod method=HttpMethod.CACHE.get(value); + if (method!=null) + field = new StaticValueHttpField(HttpHeader.C_METHOD,method.asString(),method); + else + field = new AuthorityHttpField(value); + break; - case ":status": - Integer code = Integer.valueOf(value); - field = new StaticValueHttpField(header,name,value,code); - break; + case C_STATUS: + Integer code = Integer.valueOf(value); + field = new StaticValueHttpField(HttpHeader.C_STATUS,value,code); + break; - case ":scheme": - HttpScheme scheme=HttpScheme.CACHE.get(value); - if (scheme!=null) - field = new StaticValueHttpField(header,name,scheme.asString(),scheme); - else + case C_SCHEME: + HttpScheme scheme=HttpScheme.CACHE.get(value); + if (scheme!=null) + field = new StaticValueHttpField(HttpHeader.C_SCHEME,scheme.asString(),scheme); + else + field = new AuthorityHttpField(value); + break; + + case C_AUTHORITY: field = new AuthorityHttpField(value); - break; + break; - case ":authority": - field = new AuthorityHttpField(value); - break; + case C_PATH: + field = new HttpField(HttpHeader.C_PATH,value); + break; - case ":path": - field = new HttpField(header,name,value); - break; + case CONTENT_LENGTH: + if ("0".equals(value)) + field = CONTENT_LENGTH_0; + else + field = new HttpField.LongValueHttpField(header,value); + break; - case "content-length": - if ("0".equals(value)) - field = CONTENT_LENGTH_0; - else - field = new HttpField.LongValueHttpField(header,value); - break; - - default: - field = new HttpField(header,name,value); - break; + default: + field = new HttpField(header,name,value); + break; + } } if (LOG.isDebugEnabled()) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 3832ffa1cca..35d15f51021 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -51,6 +51,7 @@ public class HpackEncoder private final static EnumSet<HttpHeader> __DO_NOT_INDEX = EnumSet.of( // TODO ??? HttpHeader.C_PATH, + // TODO ??? HttpHeader.DATE, HttpHeader.CONTENT_MD5, HttpHeader.CONTENT_RANGE, HttpHeader.ETAG, @@ -121,7 +122,6 @@ public class HpackEncoder encode(buffer,metadata); BufferUtil.flipToFlush(buffer,0); } - public void encode(ByteBuffer buffer, MetaData metadata) { @@ -161,7 +161,6 @@ public class HpackEncoder { encode(buffer,field); } - } public void encodeMaxHeaderTableSize(ByteBuffer buffer, int maxHeaderTableSize) @@ -179,14 +178,13 @@ public class HpackEncoder String encoding=null; - // TODO currently we do not check if there is enough space, so we will always - // return true or fail nastily. + // TODO currently we do not check if there is enough space, so we may fail nastily. // Is there an entry for the field? Entry entry = _context.get(field); - if (entry!=null) { + // Known field entry, so encode it as indexed int index=_context.index(entry); if (p>=0) encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index)); @@ -195,7 +193,7 @@ public class HpackEncoder } else { - // Must be a new entry, so we will have to send literally. + // Unknown field entry, so we will have to send literally. final Entry name; final boolean indexed; @@ -203,6 +201,7 @@ public class HpackEncoder final boolean huffman; final int bits; + // But do we know it's name? HttpHeader header = field.getHeader(); if (header==null) { @@ -316,7 +315,7 @@ public class HpackEncoder { int e=buffer.position(); if (LOG.isDebugEnabled()) - LOG.debug("encoded '{}' by {} to '{}'",field,encoding,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); + LOG.debug("encode {}:'{}' to '{}'",encoding,field,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); } } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 73ca0f68e22..ac045a92d0d 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -75,17 +75,17 @@ public class MetaDataBuilder if (field instanceof StaticValueHttpField) { StaticValueHttpField value = (StaticValueHttpField)field; - switch(field.getName()) + switch(field.getHeader()) { - case ":status": + case C_STATUS: _status=(Integer)value.getStaticValue(); break; - case ":method": + case C_METHOD: _method=field.getValue(); break; - case ":scheme": + case C_SCHEME: _scheme = (HttpScheme)value.getStaticValue(); break; @@ -93,27 +93,27 @@ public class MetaDataBuilder throw new IllegalArgumentException(field.getName()); } } - else + else if (field.getHeader()!=null) { - switch(field.getName()) + switch(field.getHeader()) { - case ":status": + case C_STATUS: _status=Integer.parseInt(field.getValue()); break; - case ":method": + case C_METHOD: _method=field.getValue(); break; - case ":scheme": + case C_SCHEME: _scheme = HttpScheme.CACHE.get(field.getValue()); break; - case ":authority": + case C_AUTHORITY: _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); break; - case ":path": + case C_PATH: _path = field.getValue(); break; @@ -122,6 +122,11 @@ public class MetaDataBuilder _fields.add(field); } } + else + { + if (field.getName().charAt(0)!=':') + _fields.add(field); + } } public MetaData build() @@ -130,6 +135,7 @@ public class MetaDataBuilder { HttpFields fields = _fields; _fields = new HttpFields(Math.max(10,fields.size()+5)); + if (_method!=null) return new MetaData.Request(_method,_scheme,_authority,_path,HttpVersion.HTTP_2,fields); if (_status!=0) diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index fbbc1b5c953..c0f81d58809 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -39,15 +39,13 @@ import org.junit.Test; */ public class HpackDecoderTest { - @Test - @Ignore public void testDecodeD_3() { HpackDecoder decoder = new HpackDecoder(4096,8192); // First request - String encoded="828786440f7777772e6578616d706c652e636f6d"; + String encoded="828684410f7777772e6578616d706c652e636f6d"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); @@ -60,7 +58,7 @@ public class HpackDecoderTest // Second request - encoded="5c086e6f2d6361636865"; + encoded="828684be58086e6f2d6361636865"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); @@ -76,7 +74,7 @@ public class HpackDecoderTest // Third request - encoded="30858c8b84400a637573746f6d2d6b65790c637573746f6d2d76616c7565"; + encoded="828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); From e332aa9c43915e34eb4fe5621450aa9b340f333f Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Sat, 2 Aug 2014 23:04:51 +0200 Subject: [PATCH 188/269] Improved logging. --- .../src/main/java/org/eclipse/jetty/http2/HTTP2Session.java | 5 ++++- .../main/java/org/eclipse/jetty/http2/frames/DataFrame.java | 2 +- .../java/org/eclipse/jetty/http2/frames/HeadersFrame.java | 6 ++++++ .../main/java/org/eclipse/jetty/http2/parser/Parser.java | 5 +++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index dfdc4adc20f..79c89a55a4c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -724,7 +724,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener List<ByteBuffer> byteBuffers = lease.getByteBuffers(); if (LOG.isDebugEnabled()) - LOG.debug("Writing {} buffers ({} bytes) for {}", byteBuffers.size(), lease.getTotalLength(), active); + LOG.debug("Writing {} buffers ({} bytes) for {} frames {}", byteBuffers.size(), lease.getTotalLength(), active.size(), active); endPoint.write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()])); return Action.SCHEDULED; } @@ -739,6 +739,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener complete.add(active.get(i)); active.clear(); + if (LOG.isDebugEnabled()) + LOG.debug("Written {} frames for {}", complete.size(), complete); + // Drain the queue one by one to avoid reentrancy. while (!complete.isEmpty()) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java index 03377cb1194..987a983b68b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -75,6 +75,6 @@ public class DataFrame extends Frame @Override public String toString() { - return String.format("%s{length:%d,end=%b}", super.toString(), data.remaining(), endStream); + return String.format("%s#%d{length:%d,end=%b}", super.toString(), streamId, data.remaining(), endStream); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java index 649006d2f7b..1fd2cd1778a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java @@ -55,4 +55,10 @@ public class HeadersFrame extends Frame { return endStream; } + + @Override + public String toString() + { + return String.format("%s#%d", super.toString(), streamId); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index dc447c5be0c..ac4dfaa7161 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -151,8 +151,9 @@ public class Parser } catch (Throwable x) { - LOG.debug(x); - notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "parser_error: "+x); + if (LOG.isDebugEnabled()) + LOG.debug(x); + notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "parser_error"); return false; } } From 8d554b54a85afc4b1b9eb1791d52ebf0766df406 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Sat, 2 Aug 2014 23:11:04 +0200 Subject: [PATCH 189/269] Fixed checks for headers too big. --- .../jetty/http2/generator/HeadersGenerator.java | 13 ++++++++----- .../http2/generator/PushPromiseGenerator.java | 17 ++++++++++------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index b7d4c7615e5..b19a6a8b9b8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -52,17 +52,20 @@ public class HeadersGenerator extends FrameGenerator throw new IllegalArgumentException("Invalid stream id: " + streamId); int maxFrameSize = getMaxFrameSize(); - encoder.encode(metaData, lease, maxFrameSize); - long length = lease.getTotalLength(); - if (length > maxFrameSize) - throw new IllegalArgumentException("Invalid headers, too big"); + // The lease may already contain other buffers, + // compute the bytes generated by the encoder only. + long leaseLength = lease.getTotalLength(); + encoder.encode(metaData, lease, maxFrameSize); + long headersLength = lease.getTotalLength() - leaseLength; + if (headersLength > maxFrameSize) + throw new IllegalArgumentException(String.format("Invalid headers, too big for max frame size: %d > %d", headersLength, maxFrameSize)); int flags = Flags.END_HEADERS; if (!contentFollows) flags |= Flags.END_STREAM; - ByteBuffer header = generateHeader(lease, FrameType.HEADERS, (int)length, flags, streamId); + ByteBuffer header = generateHeader(lease, FrameType.HEADERS, (int)leaseLength, flags, streamId); BufferUtil.flipToFlush(header, 0); lease.prepend(header, true); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index ed973ce3b0f..5b73aba0e48 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -54,21 +54,24 @@ public class PushPromiseGenerator extends FrameGenerator throw new IllegalArgumentException("Invalid promised stream id: " + promisedStreamId); int maxFrameSize = getMaxFrameSize(); - encoder.encode(metaData, lease, maxFrameSize); - // The promised streamId. int fixedLength = 4; + maxFrameSize -= fixedLength; - long length = lease.getTotalLength(); - if (length > maxFrameSize - fixedLength) - throw new IllegalArgumentException("Invalid headers, too big"); + // The lease may already contain other buffers, + // compute the bytes generated by the encoder only. + long leaseLength = lease.getTotalLength(); + encoder.encode(metaData, lease, maxFrameSize); + long headersLength = lease.getTotalLength() - leaseLength; + if (headersLength > maxFrameSize) + throw new IllegalArgumentException(String.format("Invalid headers, too big for max frame size: %d > %d", headersLength, maxFrameSize)); // Space for the promised streamId. - length += fixedLength; + headersLength += fixedLength; int flags = Flags.END_HEADERS; - ByteBuffer header = generateHeader(lease, FrameType.PUSH_PROMISE, (int)length, flags, streamId); + ByteBuffer header = generateHeader(lease, FrameType.PUSH_PROMISE, (int)headersLength, flags, streamId); header.putInt(promisedStreamId); BufferUtil.flipToFlush(header, 0); From 35f0103add1fc4241c18a5735aee02f01798885e Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Sun, 3 Aug 2014 00:27:16 +0200 Subject: [PATCH 190/269] Added HTTP2 tests for multiple requests. --- .../eclipse/jetty/http2/client/HTTP2Test.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index 6a6468bc959..e43069b9933 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.client; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; @@ -35,8 +36,10 @@ import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.Promise; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; public class HTTP2Test extends AbstractTest @@ -124,4 +127,48 @@ public class HTTP2Test extends AbstractTest Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } + + @Ignore + @Test + public void testMultipleRequests() throws Exception + { + final String downloadBytes = "X-Download"; + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + int download = request.getIntHeader(downloadBytes); + byte[] content = new byte[download]; + new Random().nextBytes(content); + response.getOutputStream().write(content); + } + }); + + int requests = 20; + Session session = newClient(new Session.Listener.Adapter()); + + Random random = new Random(); + HttpFields fields = new HttpFields(); + fields.putLongField(downloadBytes, random.nextInt(128 * 1024)); + fields.put("User-Agent", "HTTP2Client/" + Jetty.VERSION); + MetaData.Request metaData = newRequest("GET", fields); + HeadersFrame frame = new HeadersFrame(1, metaData, null, true); + final CountDownLatch latch = new CountDownLatch(requests); + for (int i = 0; i < requests; ++i) + { + session.newStream(frame, new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + latch.countDown(); + } + }); + } + + Assert.assertTrue(latch.await(requests, TimeUnit.SECONDS)); + } } From 17c03385d68fbf1baa4b8a8c8273a704df1928b6 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 4 Aug 2014 12:09:10 +0200 Subject: [PATCH 191/269] Fixed send() by properly handling all cases. --- .../http2/server/HttpTransportOverHTTP2.java | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 55b9daa67e8..0116485e333 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -54,19 +54,33 @@ public class HttpTransportOverHTTP2 implements HttpTransport { MetaData.Request metaData = (MetaData.Request)request.getMetaData(); boolean isHeadRequest = HttpMethod.HEAD.is(metaData.getMethod()); + + // info != null | content != 0 | last = true => commit + send/end + // info != null | content != 0 | last = false => commit + send + // info != null | content == 0 | last = true => commit/end + // info != null | content == 0 | last = false => commit + // info == null | content != 0 | last = true => send/end + // info == null | content != 0 | last = false => send + // info == null | content == 0 | last = true => send/end + // info == null | content == 0 | last = false => noop + boolean hasContent = BufferUtil.hasContent(content) && !isHeadRequest; + boolean sendContent = hasContent || (info == null && lastContent); - if (commit.compareAndSet(false, true)) + if (info != null) { - boolean endStream = !hasContent && lastContent; - commit(info, endStream, !hasContent ? callback : commitCallback); - } - else - { - callback.failed(new IllegalStateException()); + if (commit.compareAndSet(false, true)) + { + boolean endStream = !hasContent && lastContent; + commit(info, endStream, sendContent ? commitCallback : callback); + } + else + { + callback.failed(new IllegalStateException()); + } } - if (hasContent) + if (sendContent) { send(content, lastContent, callback); } @@ -107,7 +121,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport public void abort() { if (LOG.isDebugEnabled()) - LOG.debug("HTTP2 Response #{} aborted"); + LOG.debug("HTTP2 Response #{} aborted", stream.getId()); stream.getSession().disconnect(); } From a2faa030cc9cb480d5933e316e545c6bb1e02c79 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 4 Aug 2014 12:09:35 +0200 Subject: [PATCH 192/269] Improved logging. --- .../eclipse/jetty/http2/hpack/HpackEncoder.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 35d15f51021..c08d500c88d 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -127,24 +127,26 @@ public class HpackEncoder { if (LOG.isDebugEnabled()) LOG.debug(String.format("CtxTbl[%x] encoding",_context.hashCode())); - + + int pos = buffer.position(); + // Check the header table sizes! int maxHeaderTableSize=Math.min(_remoteMaxHeaderTableSize,_localMaxHeaderTableSize); if (maxHeaderTableSize!=_context.getMaxHeaderTableSize()) encodeMaxHeaderTableSize(buffer,maxHeaderTableSize); - + // Add Request/response meta fields if (metadata.isRequest()) { MetaData.Request request = (MetaData.Request)metadata; - + // TODO optimise these to avoid HttpField creation String scheme=request.getURI().getScheme(); encode(buffer,new HttpField(HttpHeader.C_SCHEME,scheme==null?HttpScheme.HTTP.asString():scheme)); encode(buffer,new HttpField(HttpHeader.C_METHOD,request.getMethod())); - encode(buffer,new HttpField(HttpHeader.C_AUTHORITY,request.getURI().getAuthority())); + encode(buffer,new HttpField(HttpHeader.C_AUTHORITY,request.getURI().getAuthority())); encode(buffer,new HttpField(HttpHeader.C_PATH,request.getURI().getPathQuery())); - + } else if (metadata.isResponse()) { @@ -155,12 +157,15 @@ public class HpackEncoder status=new HttpField(HttpHeader.C_STATUS,Integer.toString(code)); encode(buffer,status); } - + // Add all the other fields for (HttpField field : metadata) { encode(buffer,field); } + + if (LOG.isDebugEnabled()) + LOG.debug(String.format("CtxTbl[%x] encoded %d octets",_context.hashCode(), buffer.position() - pos)); } public void encodeMaxHeaderTableSize(ByteBuffer buffer, int maxHeaderTableSize) From 1c984e680f1953ffa3d97c29d814464758f1bb4a Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 4 Aug 2014 12:12:19 +0200 Subject: [PATCH 193/269] Introduced the capability of inserting buffers at a specific index. --- .../java/org/eclipse/jetty/io/ByteBufferPool.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index eca6b39af77..3ffeb1ae9fe 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -75,8 +75,7 @@ public interface ByteBufferPool public void prepend(ByteBuffer buffer, boolean recycle) { - buffers.add(0, buffer); - recycles.add(0, recycle); + insert(0, buffer, recycle); } public void append(ByteBuffer buffer, boolean recycle) @@ -85,6 +84,12 @@ public interface ByteBufferPool recycles.add(recycle); } + public void insert(int index, ByteBuffer buffer, boolean recycle) + { + buffers.add(index, buffer); + recycles.add(index, recycle); + } + public List<ByteBuffer> getByteBuffers() { return buffers; @@ -98,6 +103,11 @@ public interface ByteBufferPool return length; } + public int getSize() + { + return buffers.size(); + } + public void recycle() { for (int i = 0; i < buffers.size(); ++i) From 20925ded97cc5b868fabab867f375c219450e234 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 4 Aug 2014 12:15:14 +0200 Subject: [PATCH 194/269] Fixed insertion of frame header buffer at the right index. In case the lease is not empty, the frame header buffer must not be inserted at index 0, but just before the frame body buffer. --- .../test/java/org/eclipse/jetty/http2/client/HTTP2Test.java | 2 -- .../org/eclipse/jetty/http2/generator/HeadersGenerator.java | 5 +++-- .../eclipse/jetty/http2/generator/PushPromiseGenerator.java | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index e43069b9933..9133b46cc49 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -39,7 +39,6 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.Promise; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; public class HTTP2Test extends AbstractTest @@ -128,7 +127,6 @@ public class HTTP2Test extends AbstractTest Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } - @Ignore @Test public void testMultipleRequests() throws Exception { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index b19a6a8b9b8..9c3feffe548 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -55,6 +55,7 @@ public class HeadersGenerator extends FrameGenerator // The lease may already contain other buffers, // compute the bytes generated by the encoder only. + int leaseSize = lease.getSize(); long leaseLength = lease.getTotalLength(); encoder.encode(metaData, lease, maxFrameSize); long headersLength = lease.getTotalLength() - leaseLength; @@ -65,9 +66,9 @@ public class HeadersGenerator extends FrameGenerator if (!contentFollows) flags |= Flags.END_STREAM; - ByteBuffer header = generateHeader(lease, FrameType.HEADERS, (int)leaseLength, flags, streamId); + ByteBuffer header = generateHeader(lease, FrameType.HEADERS, (int)headersLength, flags, streamId); BufferUtil.flipToFlush(header, 0); - lease.prepend(header, true); + lease.insert(leaseSize, header, true); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index 5b73aba0e48..11ccda20564 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -60,6 +60,7 @@ public class PushPromiseGenerator extends FrameGenerator // The lease may already contain other buffers, // compute the bytes generated by the encoder only. + int leaseSize = lease.getSize(); long leaseLength = lease.getTotalLength(); encoder.encode(metaData, lease, maxFrameSize); long headersLength = lease.getTotalLength() - leaseLength; @@ -75,6 +76,6 @@ public class PushPromiseGenerator extends FrameGenerator header.putInt(promisedStreamId); BufferUtil.flipToFlush(header, 0); - lease.prepend(header, true); + lease.insert(leaseSize, header, true); } } From ac7aa4decca605034012058dca24ebf28e61ff75 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 5 Aug 2014 00:28:06 +0200 Subject: [PATCH 195/269] Flow control needs improvements. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 79c89a55a4c..47938bfd0b5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -640,6 +640,10 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { synchronized (queue) { + // The session window size may vary concurrently upon receipt of + // WINDOW_UPDATE or SETTINGS so we read it here and not in the loop. + // The stream window size is read in the loop, but it's always + // capped by the session window size. int sessionWindow = getWindowSize(); int nonStalledIndex = 0; int size = queue.size(); @@ -663,22 +667,21 @@ public abstract class HTTP2Session implements ISession, Parser.Listener continue; } - if (stream != null) + // The stream may have a smaller window than the session. + Integer streamWindow = streams.get(stream); + if (streamWindow == null) { - Integer streamWindow = streams.get(stream); - if (streamWindow == null) - { - streamWindow = stream.getWindowSize(); - streams.put(stream, streamWindow); - } + streamWindow = stream.getWindowSize(); + streams.put(stream, streamWindow); + } - // Is it a frame belonging to an already stalled stream ? - if (streamWindow <= 0) - { - flowControl.onStreamStalled(stream); - ++nonStalledIndex; - continue; - } + // Is it a frame belonging to an already stalled stream ? + if (streamWindow <= 0) + { + flowControl.onStreamStalled(stream); + ++nonStalledIndex; + // There may be *non* flow controlled frames to send. + continue; } } } @@ -888,12 +891,16 @@ public abstract class HTTP2Session implements ISession, Parser.Listener public void generate(ByteBufferPool.Lease lease) { DataFrame dataFrame = (DataFrame)frame; - int windowSize = stream.getWindowSize(); - int frameLength = dataFrame.remaining(); - this.length = Math.min(frameLength, windowSize); - generator.data(lease, dataFrame, length); + int flowControlLength = dataFrame.remaining() + dataFrame.padding(); + + int streamWindowSize = stream.getWindowSize(); + int sessionWindowSize = getWindowSize(); + int windowSize = Math.min(streamWindowSize, sessionWindowSize); + + length = Math.min(flowControlLength, windowSize); if (LOG.isDebugEnabled()) LOG.debug("Generated {}, maxLength={}", dataFrame, length); + generator.data(lease, dataFrame, length); } @Override From 48d68a49164041d2ece903735dca3c5493091ff5 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Tue, 5 Aug 2014 09:21:27 +1000 Subject: [PATCH 196/269] handle http/1 host header in http/2 --- .../java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index ac045a92d0d..2f12502695d 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -113,6 +113,12 @@ public class MetaDataBuilder _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); break; + case HOST: + if (_authority==null) + _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); + _fields.add(field); + break; + case C_PATH: _path = field.getValue(); break; From 636c7eaeae076b58d18afe691df8639acd187b41 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 5 Aug 2014 01:44:34 +0200 Subject: [PATCH 197/269] Fixed handling of max concurrent streams. There is a difference between the value set via configuration, that always refer to remote streams (streams initiated by remote peers), and the value received via SETTINGS frame, that always refer to local streams (streams initiated locally). --- .../jetty/http2/client/StreamCountTest.java | 188 ++++++++++++++++++ .../org/eclipse/jetty/http2/HTTP2Session.java | 58 ++++-- 2 files changed, 230 insertions(+), 16 deletions(-) create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java new file mode 100644 index 00000000000..286687b2873 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java @@ -0,0 +1,188 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FuturePromise; +import org.junit.Assert; +import org.junit.Test; + +public class StreamCountTest extends AbstractTest +{ + @Test + public void testServersAllowsOneStreamEnforcedByClient() throws Exception + { + startServer(new ServerSessionListener.Adapter() + { + @Override + public Map<Integer, Integer> onPreface(Session session) + { + Map<Integer, Integer> settings = new HashMap<>(); + settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, 1); + return settings; + } + + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + return new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + if (frame.isEndStream()) + { + HttpFields fields = new HttpFields(); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, fields); + stream.headers(new HeadersFrame(stream.getId(), metaData, null, true), callback); + } + } + }; + } + }); + + final CountDownLatch settingsLatch = new CountDownLatch(1); + Session session = newClient(new Session.Listener.Adapter() + { + @Override + public void onSettings(Session session, SettingsFrame frame) + { + settingsLatch.countDown(); + } + }); + + Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); + + HttpFields fields = new HttpFields(); + MetaData.Request metaData = newRequest("GET", fields); + HeadersFrame frame1 = new HeadersFrame(1, metaData, null, false); + FuturePromise<Stream> streamPromise1 = new FuturePromise<>(); + final CountDownLatch responseLatch = new CountDownLatch(1); + session.newStream(frame1, streamPromise1, new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + if (frame.isEndStream()) + responseLatch.countDown(); + } + }); + Stream stream1 = streamPromise1.get(5, TimeUnit.SECONDS); + + HeadersFrame frame2 = new HeadersFrame(3, metaData, null, false); + FuturePromise<Stream> streamPromise2 = new FuturePromise<>(); + session.newStream(frame2, streamPromise2, new Stream.Listener.Adapter()); + + try + { + streamPromise2.get(5, TimeUnit.SECONDS); + Assert.fail(); + } + catch (ExecutionException x) + { + // Expected + } + + stream1.data(new DataFrame(stream1.getId(), BufferUtil.EMPTY_BUFFER, true), new Callback.Adapter()); + Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testServersAllowsOneStreamEnforcedByServer() throws Exception + { + final CountDownLatch resetLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + HTTP2Session session = (HTTP2Session)stream.getSession(); + session.setMaxRemoteStreams(1); + + return new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + if (frame.isEndStream()) + { + HttpFields fields = new HttpFields(); + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, fields); + stream.headers(new HeadersFrame(stream.getId(), metaData, null, true), callback); + } + } + }; + } + }); + + Session session = newClient(new Session.Listener.Adapter() + { + @Override + public void onReset(Session session, ResetFrame frame) + { + resetLatch.countDown(); + } + }); + + HttpFields fields = new HttpFields(); + MetaData.Request metaData = newRequest("GET", fields); + HeadersFrame frame1 = new HeadersFrame(1, metaData, null, false); + FuturePromise<Stream> streamPromise1 = new FuturePromise<>(); + final CountDownLatch responseLatch = new CountDownLatch(1); + session.newStream(frame1, streamPromise1, new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + if (frame.isEndStream()) + responseLatch.countDown(); + } + }); + + Stream stream1 = streamPromise1.get(5, TimeUnit.SECONDS); + + HeadersFrame frame2 = new HeadersFrame(3, metaData, null, false); + FuturePromise<Stream> streamPromise2 = new FuturePromise<>(); + session.newStream(frame2, streamPromise2, new Stream.Listener.Adapter()); + + streamPromise2.get(5, TimeUnit.SECONDS); + Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); + + stream1.data(new DataFrame(stream1.getId(), BufferUtil.EMPTY_BUFFER, true), new Callback.Adapter()); + Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 79c89a55a4c..139d7afa860 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -77,7 +77,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>(); private final AtomicInteger streamIds = new AtomicInteger(); private final AtomicInteger lastStreamId = new AtomicInteger(); - private final AtomicInteger streamCount = new AtomicInteger(); + private final AtomicInteger localStreamCount = new AtomicInteger(); + private final AtomicInteger remoteStreamCount = new AtomicInteger(); private final AtomicInteger windowSize = new AtomicInteger(); private final AtomicBoolean closed = new AtomicBoolean(); private final Scheduler scheduler; @@ -86,7 +87,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final Listener listener; private final FlowControl flowControl; private final Flusher flusher; - private volatile int maxStreamCount; + private int maxLocalStreams; + private int maxRemoteStreams; public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int maxStreams, int initialStreamId) { @@ -96,11 +98,22 @@ public abstract class HTTP2Session implements ISession, Parser.Listener this.listener = listener; this.flowControl = flowControl; this.flusher = new Flusher(4); - this.maxStreamCount = maxStreams; + this.maxLocalStreams = maxStreams; + this.maxRemoteStreams = maxStreams; this.streamIds.set(initialStreamId); this.windowSize.set(flowControl.getInitialWindowSize()); } + public int getMaxRemoteStreams() + { + return maxRemoteStreams; + } + + public void setMaxRemoteStreams(int maxRemoteStreams) + { + this.maxRemoteStreams = maxRemoteStreams; + } + public Generator getGenerator() { return generator; @@ -185,9 +198,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) { - maxStreamCount = settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS); + maxLocalStreams = settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS); if (LOG.isDebugEnabled()) - LOG.debug("Updated max concurrent streams to {}", maxStreamCount); + LOG.debug("Updated max local concurrent streams to {}", maxLocalStreams); } if (settings.containsKey(SettingsFrame.INITIAL_WINDOW_SIZE)) { @@ -295,7 +308,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } @Override - public void newStream(HeadersFrame frame, final Promise<Stream> promise, Stream.Listener listener) + public void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener) { // Synchronization is necessary to atomically create // the stream id and enqueue the frame to be sent. @@ -306,12 +319,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener priority = priority == null ? null : new PriorityFrame(streamId, priority.getDependentStreamId(), priority.getWeight(), priority.isExclusive()); frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream()); - final IStream stream = createLocalStream(frame); + final IStream stream = createLocalStream(frame, promise); if (stream == null) - { - promise.failed(new IllegalStateException()); return; - } stream.updateClose(frame.isEndStream(), true); stream.setListener(listener); @@ -385,8 +395,21 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.iterate(); } - protected IStream createLocalStream(HeadersFrame frame) + protected IStream createLocalStream(HeadersFrame frame, Promise<Stream> promise) { + while (true) + { + int localCount = localStreamCount.get(); + int maxCount = maxLocalStreams; + if (maxCount >= 0 && localCount >= maxCount) + { + promise.failed(new IllegalStateException("Max local stream count " + maxCount + " exceeded")); + return null; + } + if (localStreamCount.compareAndSet(localCount, localCount + 1)) + break; + } + IStream stream = newStream(frame); int streamId = stream.getId(); if (streams.putIfAbsent(streamId, stream) == null) @@ -399,6 +422,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } else { + promise.failed(new IllegalStateException("Duplicate stream " + streamId)); return null; } } @@ -410,14 +434,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener // SPEC: exceeding max concurrent streams is treated as stream error. while (true) { - int currentStreams = streamCount.get(); - int maxStreams = maxStreamCount; - if (maxStreams >= 0 && currentStreams >= maxStreams) + int remoteCount = remoteStreamCount.get(); + int maxCount = getMaxRemoteStreams(); + if (maxCount >= 0 && remoteCount >= maxCount) { reset(new ResetFrame(streamId, ErrorCodes.REFUSED_STREAM_ERROR), disconnectOnFailure()); return null; } - if (streamCount.compareAndSet(currentStreams, currentStreams + 1)) + if (remoteStreamCount.compareAndSet(remoteCount, remoteCount + 1)) break; } @@ -453,7 +477,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener assert removed == stream; if (local) - streamCount.decrementAndGet(); + localStreamCount.decrementAndGet(); + else + remoteStreamCount.decrementAndGet(); if (LOG.isDebugEnabled()) LOG.debug("Removed {}", stream); From d7f2c42e2d1a0af6e7786537fb13a0afed6f9403 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Tue, 5 Aug 2014 12:55:12 +1000 Subject: [PATCH 198/269] misc optimisation of http2 field creation --- .../org/eclipse/jetty/http/HttpField.java | 61 +++++++++++++++++-- .../jetty/http2/hpack/HpackContext.java | 20 ++++-- .../jetty/http2/hpack/HpackDecoder.java | 30 +++------ .../jetty/http2/hpack/HpackEncoder.java | 36 +++++++---- .../jetty/http2/hpack/MetaDataBuilder.java | 7 ++- ...tpField.java => StaticTableHttpField.java} | 14 +---- 6 files changed, 107 insertions(+), 61 deletions(-) rename jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/{StaticValueHttpField.java => StaticTableHttpField.java} (78%) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index 74db3037482..cf3147d0409 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -69,9 +69,14 @@ public class HttpField return _value; } + public int getIntValue() + { + return Integer.valueOf(_value); + } + public long getLongValue() { - return StringUtil.toLong(_value); + return Long.valueOf(_value); } public String[] getValues() @@ -416,21 +421,65 @@ public class HttpField return true; } + + public static class IntValueHttpField extends HttpField + { + final int _int; + + public IntValueHttpField(HttpHeader header, String value, int intValue) + { + super(header,value); + _int=intValue; + } + + public IntValueHttpField(HttpHeader header, String value) + { + this(header,value,Integer.valueOf(value)); + } + + public IntValueHttpField(HttpHeader header, int value) + { + this(header,Integer.toString(value),value); + } + + @Override + public int getIntValue() + { + return _int; + } + + @Override + public long getLongValue() + { + return _int; + } + } public static class LongValueHttpField extends HttpField { final long _long; - public LongValueHttpField(HttpHeader header, long value) + public LongValueHttpField(HttpHeader header, String value, long longValue) { - super(header,Long.toString(value)); - _long=value; + super(header,value); + _long=longValue; } public LongValueHttpField(HttpHeader header, String value) { - super(header,value); - _long=StringUtil.toLong(value); + this(header,value,StringUtil.toLong(value)); + } + + public LongValueHttpField(HttpHeader header,long value) + { + this(header,Long.toString(value),value); + } + + + @Override + public int getIntValue() + { + return (int)_long; } @Override diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index f058885a3b6..6c929e3fa01 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -119,20 +119,20 @@ public class HpackContext switch(i) { case 2: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.GET)); + entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.GET)); break; case 3: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.POST)); + entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.POST)); break; case 6: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTP)); + entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTP)); break; case 7: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTPS)); + entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTPS)); break; case 8: case 11: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1]))); + entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1]))); break; case 9: @@ -140,7 +140,7 @@ public class HpackContext case 12: case 13: case 14: - entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1]))); + entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1]))); break; default: @@ -429,6 +429,7 @@ public class HpackContext public static class StaticEntry extends Entry { private final byte[] _huffmanValue; + private final byte _encodedField; StaticEntry(int index,HttpField field) { @@ -450,6 +451,8 @@ public class HpackContext } else _huffmanValue=null; + + _encodedField=(byte)(0x80|index); } @Override @@ -463,6 +466,11 @@ public class HpackContext { return _huffmanValue; } + + public byte getEncodedField() + { + return _encodedField; + } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index cb32ccff76a..131746908a5 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -41,7 +41,8 @@ import org.eclipse.jetty.util.log.Logger; public class HpackDecoder { public static final Logger LOG = Log.getLogger(HpackDecoder.class); - public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 = new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L); + public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 = + new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L); private final HpackContext _context; private final MetaDataBuilder _builder; @@ -191,41 +192,26 @@ public class HpackDecoder HttpField field; if (header==null) { + // just make a normal field and bypass header name lookup field = new HttpField(null,name,value); } else { + // might be worthwhile to create a value HttpField if it is indexed + // and/or of a type that may be looked up multiple times. switch(header) { - case C_METHOD: - HttpMethod method=HttpMethod.CACHE.get(value); - if (method!=null) - field = new StaticValueHttpField(HttpHeader.C_METHOD,method.asString(),method); - else - field = new AuthorityHttpField(value); - break; - case C_STATUS: - Integer code = Integer.valueOf(value); - field = new StaticValueHttpField(HttpHeader.C_STATUS,value,code); - break; - - case C_SCHEME: - HttpScheme scheme=HttpScheme.CACHE.get(value); - if (scheme!=null) - field = new StaticValueHttpField(HttpHeader.C_SCHEME,scheme.asString(),scheme); + if (indexed) + field = new HttpField.IntValueHttpField(header,value); else - field = new AuthorityHttpField(value); + field = new HttpField(header,name,value); break; case C_AUTHORITY: field = new AuthorityHttpField(value); break; - case C_PATH: - field = new HttpField(HttpHeader.C_PATH,value); - break; - case CONTENT_LENGTH: if ("0".equals(value)) field = CONTENT_LENGTH_0; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index c08d500c88d..ee297cc74c7 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -28,6 +28,7 @@ import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; +import org.eclipse.jetty.http2.hpack.HpackContext.StaticEntry; import org.eclipse.jetty.io.ByteBufferPool.Lease; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; @@ -78,6 +79,7 @@ public class HpackEncoder } private final HpackContext _context; + private final boolean _debug; private int _remoteMaxHeaderTableSize; private int _localMaxHeaderTableSize; @@ -96,6 +98,7 @@ public class HpackEncoder _context=new HpackContext(remoteMaxHeaderTableSize); _remoteMaxHeaderTableSize=remoteMaxHeaderTableSize; _localMaxHeaderTableSize=localMaxHeaderTableSize; + _debug=LOG.isDebugEnabled(); } public HpackContext getContext() @@ -154,15 +157,13 @@ public class HpackEncoder int code=response.getStatus(); HttpField status = code<__status.length?__status[code]:null; if (status==null) - status=new HttpField(HttpHeader.C_STATUS,Integer.toString(code)); + status=new HttpField.IntValueHttpField(HttpHeader.C_STATUS,code); encode(buffer,status); } // Add all the other fields for (HttpField field : metadata) - { encode(buffer,field); - } if (LOG.isDebugEnabled()) LOG.debug(String.format("CtxTbl[%x] encoded %d octets",_context.hashCode(), buffer.position() - pos)); @@ -179,7 +180,7 @@ public class HpackEncoder private void encode(ByteBuffer buffer, HttpField field) { - final int p=LOG.isDebugEnabled()?buffer.position():-1; + final int p=_debug?buffer.position():-1; String encoding=null; @@ -190,16 +191,24 @@ public class HpackEncoder if (entry!=null) { // Known field entry, so encode it as indexed - int index=_context.index(entry); - if (p>=0) - encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index)); - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,index); + if (entry.isStatic()) + { + buffer.put(((StaticEntry)entry).getEncodedField()); + if (_debug) + encoding="IdxFieldS1"; + } + else + { + int index=_context.index(entry); + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,index); + if (_debug) + encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index)); + } } else { // Unknown field entry, so we will have to send literally. - final Entry name; final boolean indexed; final boolean never_index; @@ -211,6 +220,7 @@ public class HpackEncoder if (header==null) { name = _context.get(field.getName()); + // has the custom header name been seen before? if (name==null) { @@ -226,7 +236,7 @@ public class HpackEncoder else { // known custom name, but unknown value. - // This is probably a custom field with changing value, so don't index now. + // This is probably a custom field with changing value, so don't index. indexed=false; never_index=false; huffman=true; @@ -267,7 +277,7 @@ public class HpackEncoder } } - if (p>=0) + if (_debug) { encoding="Lit"+ ((name==null)?"HuffN":("IdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(bits,_context.index(name)))))+ @@ -316,7 +326,7 @@ public class HpackEncoder _context.add(field); } - if (p>=0) + if (_debug) { int e=buffer.position(); if (LOG.isDebugEnabled()) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index 2f12502695d..5f1df1b8390 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -72,9 +72,9 @@ public class MetaDataBuilder if (_size>_maxSize) throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+_size+">"+_maxSize); - if (field instanceof StaticValueHttpField) + if (field instanceof StaticTableHttpField) { - StaticValueHttpField value = (StaticValueHttpField)field; + StaticTableHttpField value = (StaticTableHttpField)field; switch(field.getHeader()) { case C_STATUS: @@ -98,7 +98,7 @@ public class MetaDataBuilder switch(field.getHeader()) { case C_STATUS: - _status=Integer.parseInt(field.getValue()); + _status=field.getIntValue(); break; case C_METHOD: @@ -114,6 +114,7 @@ public class MetaDataBuilder break; case HOST: + // :authority fields must come first. If we have one, ignore the host header as far as authority goes. if (_authority==null) _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue()); _fields.add(field); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java similarity index 78% rename from jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java rename to jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java index 39553264753..cd1da1c910f 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticValueHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java @@ -23,19 +23,11 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; /* ------------------------------------------------------------ */ -public class StaticValueHttpField extends HttpField +public class StaticTableHttpField extends HttpField { private final Object _value; - public StaticValueHttpField(HttpHeader header,String name, String valueString, Object value) - { - super(header,name,valueString); - if (value==null) - throw new IllegalArgumentException(); - _value=value; - } - - public StaticValueHttpField(HttpHeader header,String valueString, Object value) + public StaticTableHttpField(HttpHeader header,String valueString, Object value) { super(header,header.asString(),valueString); if (value==null) @@ -43,7 +35,7 @@ public class StaticValueHttpField extends HttpField _value=value; } - public StaticValueHttpField(String name, String valueString, Object value) + public StaticTableHttpField(String name, String valueString, Object value) { super(name,valueString); if (value==null) From 6b3c8d06a9693b4924b4f9f369e523ee7a01486b Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Tue, 5 Aug 2014 16:14:53 +1000 Subject: [PATCH 199/269] partial 100 continues support in http2 --- .../server/HTTP2ServerConnectionFactory.java | 2 +- .../http2/server/HttpChannelOverHTTP2.java | 55 ++++++++++++++++--- .../jetty/server/HttpChannelOverHttp.java | 1 - 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 22a44885926..8b080691518 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -100,7 +100,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input, stream); stream.setAttribute(CHANNEL_ATTRIBUTE, channel); - channel.requestHeaders(frame); + channel.onHeadersFrame(frame); return frame.isEndStream() ? null : this; } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 2e0f6122c01..3ee7c939a7e 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -18,11 +18,14 @@ package org.eclipse.jetty.http2.server; +import java.io.IOException; import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; @@ -46,6 +49,7 @@ public class HttpChannelOverHTTP2 extends HttpChannel private static final HttpField SERVER_VERSION=new HttpField(HttpHeader.SERVER,HttpConfiguration.SERVER_VERSION); private static final HttpField POWERED_BY=new HttpField(HttpHeader.X_POWERED_BY,HttpConfiguration.SERVER_VERSION); private final Stream stream; // TODO recycle channel for new Stream? + private boolean _expect100Continue = false; public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input, Stream stream) { @@ -53,7 +57,13 @@ public class HttpChannelOverHTTP2 extends HttpChannel this.stream = stream; } - public void requestHeaders(HeadersFrame frame) + @Override + public boolean isExpecting100Continue() + { + return _expect100Continue; + } + + public void onHeadersFrame(HeadersFrame frame) { MetaData metaData = frame.getMetaData(); if (!metaData.isRequest()) @@ -63,22 +73,20 @@ public class HttpChannelOverHTTP2 extends HttpChannel } MetaData.Request request = (MetaData.Request)metaData; - - // The specification says user agents MUST support gzip encoding. - // Based on that, some browser does not send the header, but it's - // important that applications can find it (e.g. GzipFilter). HttpFields fields = request.getFields(); - if (!fields.contains(HttpHeader.ACCEPT_ENCODING, "gzip")) - fields.add(ACCEPT_ENCODING_GZIP); + + _expect100Continue = fields.contains(HttpHeader.EXPECT,HttpHeaderValue.CONTINUE.asString()); // TODO make this a better field for h2 hpack generation + HttpFields response=getResponse().getHttpFields(); if (getHttpConfiguration().getSendServerVersion()) - getResponse().getHttpFields().add(SERVER_VERSION); + response.add(SERVER_VERSION); if (getHttpConfiguration().getSendXPoweredBy()) - getResponse().getHttpFields().add(POWERED_BY); + response.add(POWERED_BY); onRequest(request); + if (frame.isEndStream()) { onRequestComplete(); @@ -127,4 +135,33 @@ public class HttpChannelOverHTTP2 extends HttpChannel onRequestComplete(); } } + + /** + * If the associated response has the Expect header set to 100 Continue, + * then accessing the input stream indicates that the handler/servlet + * is ready for the request body and thus a 100 Continue response is sent. + * + * @throws IOException if the InputStream cannot be created + */ + @Override + public void continue100(int available) throws IOException + { + // If the client is expecting 100 CONTINUE, then send it now. + // TODO: consider using an AtomicBoolean ? + if (isExpecting100Continue()) + { + _expect100Continue = false; + + // is content missing? + if (available == 0) + { + if (getResponse().isCommitted()) + throw new IOException("Committed before 100 Continues"); + + boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false); + if (!committed) + throw new IOException("Concurrent commit while trying to send 100-Continue"); + } + } + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index ae8c6143441..625213050eb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -199,7 +199,6 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl if (getResponse().isCommitted()) throw new IOException("Committed before 100 Continues"); - // TODO: break this dependency with HttpGenerator boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false); if (!committed) throw new IOException("Concurrent commit while trying to send 100-Continue"); From bec34b460fc370d10b3bc92bee5a09a1787c6f8f Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Tue, 5 Aug 2014 17:26:27 +1000 Subject: [PATCH 200/269] optimised HttpFields --- .../org/eclipse/jetty/http/HttpFields.java | 158 +++++++++++------- .../eclipse/jetty/http/HttpFieldsTest.java | 154 ++++++++++++----- .../server/ForwardedRequestCustomizer.java | 6 +- .../org/eclipse/jetty/server/Request.java | 4 +- .../org/eclipse/jetty/server/Response.java | 2 +- .../jetty/server/PartialRFC2616Test.java | 2 +- .../eclipse/jetty/server/ResponseTest.java | 26 +-- .../jetty/test/rfcs/RFC2616BaseTest.java | 2 +- .../jetty/server/session/IdleSessionTest.java | 2 +- .../server/session/DirtyAttributeTest.java | 2 +- .../session/MaxInactiveMigrationTest.java | 2 +- .../ModifyMaxInactiveIntervalTest.java | 2 +- .../ReloadedSessionMissingClassTest.java | 2 +- .../server/session/SaveIntervalTest.java | 2 +- .../server/session/SessionExpiryTest.java | 2 +- .../mongodb/PurgeInvalidSessionTest.java | 2 +- .../nosql/mongodb/PurgeValidSessionTest.java | 2 +- .../nosql/mongodb/SessionSavingValueTest.java | 4 +- .../StopSessionManagerDeleteSessionTest.java | 2 +- ...AbstractClientCrossContextSessionTest.java | 2 +- .../session/AbstractImmortalSessionTest.java | 2 +- .../AbstractInvalidationSessionTest.java | 2 +- .../session/AbstractLastAccessTimeTest.java | 4 +- .../server/session/AbstractLightLoadTest.java | 2 +- .../AbstractLocalSessionScavengingTest.java | 2 +- .../session/AbstractNewSessionTest.java | 2 +- .../session/AbstractOrphanedSessionTest.java | 2 +- .../AbstractProxySerializationTest.java | 2 +- .../session/AbstractRemoveSessionTest.java | 2 +- .../session/AbstractSessionCookieTest.java | 2 +- .../session/AbstractSessionExpiryTest.java | 4 +- ...bstractSessionInvalidateAndCreateTest.java | 2 +- .../session/AbstractSessionMigrationTest.java | 2 +- .../session/AbstractSessionRenewTest.java | 4 +- .../AbstractSessionValueSavingTest.java | 4 +- ...StopSessionManagerPreserveSessionTest.java | 2 +- .../AbstractWebAppObjectInSessionTest.java | 2 +- 37 files changed, 265 insertions(+), 157 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 278be78cd83..0779a5ae6b1 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -19,8 +19,10 @@ package org.eclipse.jetty.http; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.ConcurrentModificationException; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -34,7 +36,6 @@ import java.util.StringTokenizer; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.QuotedStringTokenizer; -import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -55,11 +56,12 @@ public class HttpFields implements Iterable<HttpField> private static final Logger LOG = Log.getLogger(HttpFields.class); - private final List<HttpField> _fields; + private HttpField[] _fields; + private int _size; public HttpFields() { - _fields=new ArrayList<>(); + _fields=new HttpField[20]; } /** @@ -67,18 +69,18 @@ public class HttpFields implements Iterable<HttpField> */ public HttpFields(int capacity) { - _fields=new ArrayList<>(capacity); + _fields=new HttpField[capacity]; } public int size() { - return _fields.size(); + return _size; } @Override public Iterator<HttpField> iterator() { - return _fields.iterator(); + return new Itr(); } /** @@ -86,7 +88,7 @@ public class HttpFields implements Iterable<HttpField> */ public Collection<String> getFieldNamesCollection() { - final Set<String> list = new HashSet<>(_fields.size()); + final Set<String> list = new HashSet<>(_size); for (HttpField f : this) { if (f!=null) @@ -111,14 +113,16 @@ public class HttpFields implements Iterable<HttpField> */ public HttpField getField(int i) { - return _fields.get(i); + if (i>=_size) + throw new NoSuchElementException(); + return _fields[i]; } public HttpField getField(HttpHeader header) { - for (int i=0;i<_fields.size();i++) + for (int i=0;i<_size;i++) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.getHeader()==header) return f; } @@ -127,9 +131,9 @@ public class HttpFields implements Iterable<HttpField> public HttpField getField(String name) { - for (int i=0;i<_fields.size();i++) + for (int i=0;i<_size;i++) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.getName().equalsIgnoreCase(name)) return f; } @@ -138,9 +142,9 @@ public class HttpFields implements Iterable<HttpField> public boolean contains(HttpField field) { - for (int i=_fields.size();i-->0;) + for (int i=_size;i-->0;) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.isSameName(field) && f.contains(field.getValue())) return true; } @@ -149,9 +153,9 @@ public class HttpFields implements Iterable<HttpField> public boolean contains(HttpHeader header, String value) { - for (int i=_fields.size();i-->0;) + for (int i=_size;i-->0;) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.getHeader()==header && f.contains(value)) return true; } @@ -160,9 +164,9 @@ public class HttpFields implements Iterable<HttpField> public boolean contains(String name, String value) { - for (int i=_fields.size();i-->0;) + for (int i=_size;i-->0;) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.getName().equalsIgnoreCase(name) && f.contains(value)) return true; } @@ -172,39 +176,35 @@ public class HttpFields implements Iterable<HttpField> public boolean containsKey(String name) { - for (int i=_fields.size();i-->0;) + for (int i=_size;i-->0;) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.getName().equalsIgnoreCase(name)) return true; } return false; } - public String getStringField(HttpHeader header) - { - return getStringField(header.asString()); - } - public String get(HttpHeader header) { - return getStringField(header.asString()); + for (int i=0;i<_size;i++) + { + HttpField f=_fields[i]; + if (f.getHeader()==header) + return f.getValue(); + } + return null; } public String get(String header) { - return getStringField(header); - } - - /** - * @return the value of a field, or null if not found. For multiple fields of the same name, - * only the first is returned. - * @param name the case-insensitive field name - */ - public String getStringField(String name) - { - HttpField field = getField(name); - return field==null?null:field.getValue(); + for (int i=0;i<_size;i++) + { + HttpField f=_fields[i]; + if (f.getName().equalsIgnoreCase(header)) + return f.getValue(); + } + return null; } /** @@ -230,9 +230,9 @@ public class HttpFields implements Iterable<HttpField> */ public Enumeration<String> getValues(final String name) { - for (int i=0;i<_fields.size();i++) + for (int i=0;i<_size;i++) { - final HttpField f = _fields.get(i); + final HttpField f = _fields[i]; if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null) { @@ -247,9 +247,9 @@ public class HttpFields implements Iterable<HttpField> { if (field==null) { - while (i<_fields.size()) + while (i<_size) { - field=_fields.get(i++); + field=_fields[i++]; if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null) return true; } @@ -270,7 +270,6 @@ public class HttpFields implements Iterable<HttpField> } throw new NoSuchElementException(); } - }; } } @@ -328,22 +327,24 @@ public class HttpFields implements Iterable<HttpField> public void put(HttpField field) { boolean put=false; - for (int i=_fields.size();i-->0;) + for (int i=_size;i-->0;) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.isSameName(field)) { if (put) - _fields.remove(i); + { + System.arraycopy(_fields,i+1,_fields,i,--_size-i); + } else { - _fields.set(i,field); + _fields[i]=field; put=true; } } } if (!put) - _fields.add(field); + add(field); } /** @@ -408,7 +409,7 @@ public class HttpFields implements Iterable<HttpField> return; HttpField field = new HttpField(name, value); - _fields.add(field); + add(field); } public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException @@ -429,7 +430,7 @@ public class HttpFields implements Iterable<HttpField> if (value == null) throw new IllegalArgumentException("null value"); HttpField field = new HttpField(header, value); - _fields.add(field); + add(field); } /** @@ -439,13 +440,17 @@ public class HttpFields implements Iterable<HttpField> */ public HttpField remove(HttpHeader name) { - for (int i=_fields.size();i-->0;) + HttpField removed=null; + for (int i=_size;i-->0;) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.getHeader()==name) - return _fields.remove(i); + { + removed=f; + System.arraycopy(_fields,i+1,_fields,i,--_size-i); + } } - return null; + return removed; } /** @@ -455,13 +460,17 @@ public class HttpFields implements Iterable<HttpField> */ public HttpField remove(String name) { - for (int i=_fields.size();i-->0;) + HttpField removed=null; + for (int i=_size;i-->0;) { - HttpField f=_fields.get(i); + HttpField f=_fields[i]; if (f.getName().equalsIgnoreCase(name)) - return _fields.remove(i); + { + removed=f; + System.arraycopy(_fields,i+1,_fields,i,--_size-i); + } } - return null; + return removed; } /** @@ -622,17 +631,20 @@ public class HttpFields implements Iterable<HttpField> public void clear() { - _fields.clear(); + _size=0; } public void add(HttpField field) { - _fields.add(field); + if (_size==_fields.length) + _fields=Arrays.copyOf(_fields,_size*2); + _fields[_size++]=field; } public void addAll(HttpFields fields) { - _fields.addAll(fields._fields); + for (int i=0;i<fields._size;i++) + add(fields._fields[i]); } /** @@ -808,5 +820,29 @@ public class HttpFields implements Iterable<HttpField> } + private class Itr implements Iterator<HttpField> + { + int _cursor; // index of next element to return + + public boolean hasNext() + { + return _cursor != _size; + } + + @SuppressWarnings("unchecked") + public HttpField next() + { + int i = _cursor; + if (i >= _size) + throw new NoSuchElementException(); + _cursor = i + 1; + return _fields[i]; + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index ed2bef169ea..150bfa75687 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -26,10 +26,13 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.nio.ByteBuffer; +import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Locale; +import java.util.NoSuchElementException; import java.util.Set; + import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; import org.junit.Assert; @@ -48,9 +51,10 @@ public class HttpFieldsTest header.put("name0", "value:0"); header.put("name1", "value1"); - assertEquals("value:0",header.getStringField("name0")); - assertEquals("value1",header.getStringField("name1")); - assertNull(header.getStringField("name2")); + assertEquals(2,header.size()); + assertEquals("value:0",header.get("name0")); + assertEquals("value1",header.get("name1")); + assertNull(header.get("name2")); int matches=0; Enumeration<String> e = header.getFieldNames(); @@ -68,6 +72,7 @@ public class HttpFieldsTest assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value:0"); assertEquals(false, e.hasMoreElements()); + } @Test @@ -99,10 +104,45 @@ public class HttpFieldsTest header.put("name0", "value0"); header.put("name1", "value1"); - assertEquals("value0",header.getStringField("name0")); - assertEquals("value0",header.getStringField("Name0")); - assertEquals("value1",header.getStringField("name1")); - assertEquals("value1",header.getStringField("Name1")); + assertEquals("value0",header.get("name0")); + assertEquals("value0",header.get("Name0")); + assertEquals("value1",header.get("name1")); + assertEquals("value1",header.get("Name1")); + assertEquals(null,header.get("Name2")); + + assertEquals("value0",header.getField("name0").getValue()); + assertEquals("value0",header.getField("Name0").getValue()); + assertEquals("value1",header.getField("name1").getValue()); + assertEquals("value1",header.getField("Name1").getValue()); + assertEquals(null,header.getField("Name2")); + + assertEquals("value0",header.getField(0).getValue()); + assertEquals("value1",header.getField(1).getValue()); + try + { + header.getField(2); + Assert.fail(); + } + catch(NoSuchElementException e) + {} + } + + @Test + public void testGetKnown() throws Exception + { + HttpFields header = new HttpFields(); + + header.put("Connection", "value0"); + header.put(HttpHeader.ACCEPT, "value1"); + + assertEquals("value0",header.get(HttpHeader.CONNECTION)); + assertEquals("value1",header.get(HttpHeader.ACCEPT)); + + assertEquals("value0",header.getField(HttpHeader.CONNECTION).getValue()); + assertEquals("value1",header.getField(HttpHeader.ACCEPT).getValue()); + + assertEquals(null,header.getField(HttpHeader.AGE)); + assertEquals(null,header.get(HttpHeader.AGE)); } @Test @@ -153,16 +193,16 @@ public class HttpFieldsTest header.put("name1", "xxxxxx"); header.put("name2", "value2"); - assertEquals("value0",header.getStringField("name0")); - assertEquals("xxxxxx",header.getStringField("name1")); - assertEquals("value2",header.getStringField("name2")); + assertEquals("value0",header.get("name0")); + assertEquals("xxxxxx",header.get("name1")); + assertEquals("value2",header.get("name2")); header.put("name1", "value1"); - assertEquals("value0",header.getStringField("name0")); - assertEquals("value1",header.getStringField("name1")); - assertEquals("value2",header.getStringField("name2")); - assertNull(header.getStringField("name3")); + assertEquals("value0",header.get("name0")); + assertEquals("value1",header.get("name1")); + assertEquals("value2",header.get("name2")); + assertNull(header.get("name3")); int matches=0; Enumeration<String> e = header.getFieldNames(); @@ -188,22 +228,22 @@ public class HttpFieldsTest @Test public void testRemovePut() throws Exception { - HttpFields header = new HttpFields(); + HttpFields header = new HttpFields(1); header.put("name0", "value0"); header.put("name1", "value1"); header.put("name2", "value2"); - assertEquals("value0",header.getStringField("name0")); - assertEquals("value1",header.getStringField("name1")); - assertEquals("value2",header.getStringField("name2")); + assertEquals("value0",header.get("name0")); + assertEquals("value1",header.get("name1")); + assertEquals("value2",header.get("name2")); header.remove("name1"); - assertEquals("value0",header.getStringField("name0")); - assertNull(header.getStringField("name1")); - assertEquals("value2",header.getStringField("name2")); - assertNull(header.getStringField("name3")); + assertEquals("value0",header.get("name0")); + assertNull(header.get("name1")); + assertEquals("value2",header.get("name2")); + assertNull(header.get("name3")); int matches=0; Enumeration<String> e = header.getFieldNames(); @@ -232,16 +272,16 @@ public class HttpFieldsTest fields.add("name1", "valueA"); fields.add("name2", "value2"); - assertEquals("value0",fields.getStringField("name0")); - assertEquals("valueA",fields.getStringField("name1")); - assertEquals("value2",fields.getStringField("name2")); + assertEquals("value0",fields.get("name0")); + assertEquals("valueA",fields.get("name1")); + assertEquals("value2",fields.get("name2")); fields.add("name1", "valueB"); - assertEquals("value0",fields.getStringField("name0")); - assertEquals("valueA",fields.getStringField("name1")); - assertEquals("value2",fields.getStringField("name2")); - assertNull(fields.getStringField("name3")); + assertEquals("value0",fields.get("name0")); + assertEquals("valueA",fields.get("name1")); + assertEquals("value2",fields.get("name2")); + assertNull(fields.get("name3")); int matches=0; Enumeration<String> e = fields.getFieldNames(); @@ -346,7 +386,7 @@ public class HttpFieldsTest assertEquals(951825600000L,d5); fields.putDateField("D2",d1); - assertEquals("Fri, 31 Dec 1999 23:59:59 GMT",fields.getStringField("D2")); + assertEquals("Fri, 31 Dec 1999 23:59:59 GMT",fields.get("D2")); } @Test @@ -355,16 +395,16 @@ public class HttpFieldsTest HttpFields fields = new HttpFields(); fields.putDateField("Dzero",0); - assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.getStringField("Dzero")); + assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.get("Dzero")); fields.putDateField("Dminus",-1); - assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.getStringField("Dminus")); + assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.get("Dminus")); fields.putDateField("Dminus",-1000); - assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.getStringField("Dminus")); + assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.get("Dminus")); fields.putDateField("Dancient",Long.MIN_VALUE); - assertEquals("Sun, 02 Dec 55 16:47:04 GMT",fields.getStringField("Dancient")); + assertEquals("Sun, 02 Dec 55 16:47:04 GMT",fields.get("Dancient")); } @Test @@ -374,15 +414,33 @@ public class HttpFieldsTest header.put("I1", "42"); header.put("I2", " 43 99"); - header.put("I3", "-44;"); + header.put("I3", "-44"); header.put("I4", " - 45abc"); header.put("N1", " - "); header.put("N2", "xx"); long i1=header.getLongField("I1"); - long i2=header.getLongField("I2"); + try + { + header.getLongField("I2"); + assertTrue(false); + } + catch(NumberFormatException e) + { + assertTrue(true); + } + long i3=header.getLongField("I3"); - long i4=header.getLongField("I4"); + + try + { + header.getLongField("I4"); + assertTrue(false); + } + catch(NumberFormatException e) + { + assertTrue(true); + } try{ header.getLongField("N1"); @@ -403,14 +461,12 @@ public class HttpFieldsTest } assertEquals(42,i1); - assertEquals(43,i2); assertEquals(-44,i3); - assertEquals(-45,i4); header.putLongField("I5", 46); header.putLongField("I6",-47); - assertEquals("46",header.getStringField("I5")); - assertEquals("-47",header.getStringField("I6")); + assertEquals("46",header.get("I5")); + assertEquals("-47",header.get("I6")); } @@ -429,12 +485,28 @@ public class HttpFieldsTest header.add("n6", "def"); header.add("N6", "hig"); header.add("n7", "abc , def;q=0.9 , hig"); + header.add("n8", "abc , def;q=0 , hig"); + header.add(HttpHeader.ACCEPT, "abc , def;q=0 , hig"); for (int i=0;i<8;i++) { + assertTrue(header.containsKey("n"+i)); + assertTrue(header.containsKey("N"+i)); assertFalse(""+i,header.contains("n"+i,"xyz")); assertEquals(""+i,i>=4,header.contains("n"+i,"def")); } + + + assertTrue(header.contains(new HttpField("N5","def"))); + assertTrue(header.contains(new HttpField("accept","abc"))); + assertTrue(header.contains(HttpHeader.ACCEPT,"abc")); + assertFalse(header.contains(new HttpField("N5","xyz"))); + assertFalse(header.contains(new HttpField("N8","def"))); + assertFalse(header.contains(HttpHeader.ACCEPT,"def")); + assertFalse(header.contains(HttpHeader.AGE,"abc")); + + assertFalse(header.containsKey("n11")); + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java index f2943cfa5e6..0ddb9634196 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java @@ -202,13 +202,13 @@ public class ForwardedRequestCustomizer implements Customizer // Do SSL first if (getForwardedCipherSuiteHeader()!=null) { - String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader()); + String cipher_suite=httpFields.get(getForwardedCipherSuiteHeader()); if (cipher_suite!=null) request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite); } if (getForwardedSslSessionIdHeader()!=null) { - String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader()); + String ssl_session_id=httpFields.get(getForwardedSslSessionIdHeader()); if(ssl_session_id!=null) { request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id); @@ -260,7 +260,7 @@ public class ForwardedRequestCustomizer implements Customizer if (header == null) return null; - String headerValue = fields.getStringField(header); + String headerValue = fields.get(header); if (headerValue == null) return null; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 4b1c23d4929..bcc992e703c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -510,7 +510,7 @@ public class Request implements HttpServletRequest @Override public String getContentType() { - String content_type = _metadata.getFields().getStringField(HttpHeader.CONTENT_TYPE); + String content_type = _metadata.getFields().get(HttpHeader.CONTENT_TYPE); if (_characterEncoding==null && content_type!=null) { MimeTypes.Type mime = MimeTypes.CACHE.get(content_type); @@ -603,7 +603,7 @@ public class Request implements HttpServletRequest @Override public String getHeader(String name) { - return _metadata==null?null:_metadata.getFields().getStringField(name); + return _metadata==null?null:_metadata.getFields().get(name); } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 366805a6f27..d8b30d246e3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -830,7 +830,7 @@ public class Response implements HttpServletResponse @Override public String getHeader(String name) { - return _fields.getStringField(name); + return _fields.get(name); } @Override diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java index bfb52afab07..62a29c20c75 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java @@ -102,7 +102,7 @@ public class PartialRFC2616Test assertEquals("3.3.1 RFC 850 ANSI C",d3,d2); fields.putDateField("Date",d1.getTime()); - assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.getStringField("Date")); + assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.get("Date")); } catch (Exception e) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index e68b6a0a4cc..d5191f9863c 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -607,7 +607,7 @@ public class ResponseTest response.addCookie(cookie); - String set = response.getHttpFields().getStringField("Set-Cookie"); + String set = response.getHttpFields().get("Set-Cookie"); assertEquals("name=value;Version=1;Path=/path;Domain=domain;Secure;HttpOnly;Comment=comment", set); } @@ -669,23 +669,23 @@ public class ResponseTest HttpFields fields = response.getHttpFields(); response.addSetCookie("null",null,null,null,-1,null,false,false,-1); - assertEquals("null=",fields.getStringField("Set-Cookie")); + assertEquals("null=",fields.get("Set-Cookie")); fields.clear(); response.addSetCookie("minimal","value",null,null,-1,null,false,false,-1); - assertEquals("minimal=value",fields.getStringField("Set-Cookie")); + assertEquals("minimal=value",fields.get("Set-Cookie")); fields.clear(); //test cookies with same name, domain and path, only 1 allowed response.addSetCookie("everything","wrong","domain","path",0,"to be replaced",true,true,0); response.addSetCookie("everything","value","domain","path",0,"comment",true,true,0); - assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",fields.getStringField("Set-Cookie")); + assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",fields.get("Set-Cookie")); Enumeration<String> e =fields.getValues("Set-Cookie"); assertTrue(e.hasMoreElements()); assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",e.nextElement()); assertFalse(e.hasMoreElements()); - assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.getStringField("Expires")); + assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.get("Expires")); assertFalse(e.hasMoreElements()); //test cookies with same name, different domain @@ -744,31 +744,31 @@ public class ResponseTest fields.clear(); response.addSetCookie("ev erything","va lue","do main","pa th",1,"co mment",true,true,1); - String setCookie=fields.getStringField("Set-Cookie"); + String setCookie=fields.get("Set-Cookie"); assertThat(setCookie,Matchers.startsWith("\"ev erything\"=\"va lue\";Version=1;Path=\"pa th\";Domain=\"do main\";Expires=")); assertThat(setCookie,Matchers.endsWith(" GMT;Max-Age=1;Secure;HttpOnly;Comment=\"co mment\"")); fields.clear(); response.addSetCookie("name","value",null,null,-1,null,false,false,0); - setCookie=fields.getStringField("Set-Cookie"); + setCookie=fields.get("Set-Cookie"); assertEquals(-1,setCookie.indexOf("Version=")); fields.clear(); response.addSetCookie("name","v a l u e",null,null,-1,null,false,false,0); - setCookie=fields.getStringField("Set-Cookie"); + setCookie=fields.get("Set-Cookie"); fields.clear(); response.addSetCookie("json","{\"services\":[\"cwa\", \"aa\"]}",null,null,-1,null,false,false,-1); - assertEquals("json=\"{\\\"services\\\":[\\\"cwa\\\", \\\"aa\\\"]}\"",fields.getStringField("Set-Cookie")); + assertEquals("json=\"{\\\"services\\\":[\\\"cwa\\\", \\\"aa\\\"]}\"",fields.get("Set-Cookie")); fields.clear(); response.addSetCookie("name","value","domain",null,-1,null,false,false,-1); response.addSetCookie("name","other","domain",null,-1,null,false,false,-1); - assertEquals("name=other;Domain=domain",fields.getStringField("Set-Cookie")); + assertEquals("name=other;Domain=domain",fields.get("Set-Cookie")); response.addSetCookie("name","more","domain",null,-1,null,false,false,-1); - assertEquals("name=more;Domain=domain",fields.getStringField("Set-Cookie")); + assertEquals("name=more;Domain=domain",fields.get("Set-Cookie")); response.addSetCookie("foo","bar","domain",null,-1,null,false,false,-1); response.addSetCookie("foo","bob","domain",null,-1,null,false,false,-1); - assertEquals("name=more;Domain=domain",fields.getStringField("Set-Cookie")); + assertEquals("name=more;Domain=domain",fields.get("Set-Cookie")); e=fields.getValues("Set-Cookie"); assertEquals("name=more;Domain=domain",e.nextElement()); @@ -776,7 +776,7 @@ public class ResponseTest fields.clear(); response.addSetCookie("name","value%=",null,null,-1,null,false,false,0); - setCookie=fields.getStringField("Set-Cookie"); + setCookie=fields.get("Set-Cookie"); assertEquals("name=value%=",setCookie); } diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java index ae891279c7b..1543084fda8 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java @@ -146,7 +146,7 @@ public abstract class RFC2616BaseTest // Test formatting fields.putDateField("Date",expected.getTime().getTime()); - Assert.assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.getStringField("Date")); + Assert.assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.get("Date")); } /** diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java index 4bcfdd86bb7..8e2d444e8dd 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java @@ -133,7 +133,7 @@ public class IdleSessionTest //make a request to set up a session on the server ContentResponse response = client.GET(url + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java index 871ea43ee42..557a498cc5c 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java @@ -77,7 +77,7 @@ public class DirtyAttributeTest ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/MaxInactiveMigrationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/MaxInactiveMigrationTest.java index cd8db0795d4..fd6ac0aa707 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/MaxInactiveMigrationTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/MaxInactiveMigrationTest.java @@ -103,7 +103,7 @@ public class MaxInactiveMigrationTest ContentResponse response = request.send(); assertEquals(HttpServletResponse.SC_OK, response.getStatus()); - sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue( sessionCookie != null ); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java index 5f9427903ab..b63b8ae2687 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java @@ -70,7 +70,7 @@ public class ModifyMaxInactiveIntervalTest ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java index aaf62e212b7..34f4e2fd65c 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java @@ -104,7 +104,7 @@ public class ReloadedSessionMissingClassTest ContentResponse response = client.GET("http://localhost:" + port1 + contextPath +"/bar?action=set"); assertEquals( HttpServletResponse.SC_OK, response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); String sessionId = (String)webApp.getServletContext().getAttribute("foo"); assertNotNull(sessionId); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java index d965d687841..aa307ffbaaa 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java @@ -77,7 +77,7 @@ public class SaveIntervalTest // Perform a request to create a session ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java index 37661e8892f..af5da2be1b4 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java @@ -102,7 +102,7 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest //make a request to set up a session on the server ContentResponse response1 = client.GET(url + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeInvalidSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeInvalidSessionTest.java index fce3a610d43..f1a4aecf78d 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeInvalidSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeInvalidSessionTest.java @@ -94,7 +94,7 @@ public class PurgeInvalidSessionTest //Create a session ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeValidSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeValidSessionTest.java index 77e04240c8a..43c7d42e47b 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeValidSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeValidSessionTest.java @@ -97,7 +97,7 @@ public class PurgeValidSessionTest //Create a session ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java index 946f4f66f89..f0f7d90eb06 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java @@ -117,7 +117,7 @@ public class SessionSavingValueTest extends AbstractSessionValueSavingTest sessionTestValue = sessionTestResponse; - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=","$1\\$Path="); @@ -144,7 +144,7 @@ public class SessionSavingValueTest extends AbstractSessionValueSavingTest sessionTestValue = sessionTestResponse; - String setCookie = response2.getHeaders().getStringField("Set-Cookie"); + String setCookie = response2.getHeaders().get("Set-Cookie"); if (setCookie != null) sessionCookie = setCookie.replaceFirst("(\\W)(P|p)ath=","$1\\$Path="); diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/StopSessionManagerDeleteSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/StopSessionManagerDeleteSessionTest.java index 03d959cbe07..478873ec5e2 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/StopSessionManagerDeleteSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/StopSessionManagerDeleteSessionTest.java @@ -86,7 +86,7 @@ public class StopSessionManagerDeleteSessionTest //Create a session ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java index 011f2e256a3..fe1a4060af4 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java @@ -74,7 +74,7 @@ public abstract class AbstractClientCrossContextSessionTest ContentResponse response = client.GET("http://localhost:" + port + contextA + servletMapping); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java index 7c04a93eca8..26ec1f4afd3 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java @@ -64,7 +64,7 @@ public abstract class AbstractImmortalSessionTest int value = 42; ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=set&value=" + value); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java index 001b3e029c9..f99df0c699d 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java @@ -79,7 +79,7 @@ public abstract class AbstractInvalidationSessionTest ContentResponse response1 = client.GET(urls[0] + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java index 67aa0f7aab1..1eb62b13c05 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java @@ -87,7 +87,7 @@ public abstract class AbstractLastAccessTimeTest ContentResponse response1 = client.GET("http://localhost:" + port1 + contextPath + servletMapping + "?action=init"); assertEquals(HttpServletResponse.SC_OK, response1.getStatus()); assertEquals("test", response1.getContentAsString()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue( sessionCookie != null ); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); @@ -106,7 +106,7 @@ public abstract class AbstractLastAccessTimeTest assertEquals(HttpServletResponse.SC_OK , response2.getStatus()); assertEquals("test", response2.getContentAsString()); - String setCookie = response2.getHeaders().getStringField("Set-Cookie"); + String setCookie = response2.getHeaders().get("Set-Cookie"); if (setCookie!=null) sessionCookie = setCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java index 56df9033dda..9e88651752b 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java @@ -82,7 +82,7 @@ public abstract class AbstractLightLoadTest ContentResponse response1 = client.GET(urls[0] + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().getStringField( "Set-Cookie" ); + String sessionCookie = response1.getHeaders().get( "Set-Cookie" ); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java index 5d25542dae0..872ed3d4ab9 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java @@ -86,7 +86,7 @@ public abstract class AbstractLocalSessionScavengingTest // Create the session on node1 ContentResponse response1 = client.GET(urls[0] + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java index 8ec7ddcc8cb..dce05a730ab 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java @@ -74,7 +74,7 @@ public abstract class AbstractNewSessionTest { ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java index 7bb9e7b57e2..1a48ccbb998 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java @@ -74,7 +74,7 @@ public abstract class AbstractOrphanedSessionTest // Connect to server1 to create a session and get its session cookie ContentResponse response1 = client.GET("http://localhost:" + port1 + contextPath + servletMapping + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java index 03dab1b070d..2999faaec32 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java @@ -101,7 +101,7 @@ public abstract class AbstractProxySerializationTest { ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractRemoveSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractRemoveSessionTest.java index 24f39687d79..9b684243a3a 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractRemoveSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractRemoveSessionTest.java @@ -66,7 +66,7 @@ public abstract class AbstractRemoveSessionTest { ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCookieTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCookieTest.java index 8cefb73f0af..3fb5585366f 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCookieTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCookieTest.java @@ -81,7 +81,7 @@ public abstract class AbstractSessionCookieTest ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. //sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java index dc4ce28be53..3d41393feb5 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java @@ -75,7 +75,7 @@ public abstract class AbstractSessionExpiryTest //make a request to set up a session on the server ContentResponse response = client.GET(url + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); @@ -125,7 +125,7 @@ public abstract class AbstractSessionExpiryTest //make a request to set up a session on the server ContentResponse response1 = client.GET(url + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java index f1c3c4c0369..0d558e5d3b3 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java @@ -119,7 +119,7 @@ public abstract class AbstractSessionInvalidateAndCreateTest // Create the session ContentResponse response1 = client.GET(url + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java index d6532eb9fc0..6bdb1d01871 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java @@ -72,7 +72,7 @@ public abstract class AbstractSessionMigrationTest Request request1 = client.POST("http://localhost:" + port1 + contextPath + servletMapping + "?action=set&value=" + value); ContentResponse response1 = request1.send(); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java index e9326153da4..80e7856e41d 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java @@ -70,7 +70,7 @@ public abstract class AbstractSessionRenewTest ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); assertFalse(testListener.isCalled()); @@ -79,7 +79,7 @@ public abstract class AbstractSessionRenewTest request.header("Cookie", sessionCookie); ContentResponse renewResponse = request.send(); assertEquals(HttpServletResponse.SC_OK,renewResponse.getStatus()); - String renewSessionCookie = renewResponse.getHeaders().getStringField("Set-Cookie"); + String renewSessionCookie = renewResponse.getHeaders().get("Set-Cookie"); assertNotNull(renewSessionCookie); assertNotSame(sessionCookie, renewSessionCookie); assertTrue(testListener.isCalled()); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionValueSavingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionValueSavingTest.java index 7cb0e9252bc..26e7bf6af3c 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionValueSavingTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionValueSavingTest.java @@ -72,7 +72,7 @@ public abstract class AbstractSessionValueSavingTest sessionTestValue = Long.parseLong(response1.getContentAsString()); - String sessionCookie = response1.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue( sessionCookie != null ); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); @@ -95,7 +95,7 @@ public abstract class AbstractSessionValueSavingTest assertTrue(sessionTestValue < Long.parseLong(response2.getContentAsString())); sessionTestValue = Long.parseLong(response2.getContentAsString()); - String setCookie = response1.getHeaders().getStringField("Set-Cookie"); + String setCookie = response1.getHeaders().get("Set-Cookie"); if (setCookie!=null) sessionCookie = setCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java index 41247daf677..28987c53c3a 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java @@ -74,7 +74,7 @@ public abstract class AbstractStopSessionManagerPreserveSessionTest //Create a session ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java index c2c614428c6..02b912ea9fd 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java @@ -120,7 +120,7 @@ public abstract class AbstractWebAppObjectInSessionTest ContentResponse response = request.send(); assertEquals( HttpServletResponse.SC_OK, response.getStatus()); - String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); From a00e65cb1f14f048db93b594da7ed0de22a1d353 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Tue, 5 Aug 2014 17:43:31 +1000 Subject: [PATCH 201/269] optimised HttpFields fixes --- .../main/java/org/eclipse/jetty/http/HttpFields.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 0779a5ae6b1..393b6719f81 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -823,25 +823,30 @@ public class HttpFields implements Iterable<HttpField> private class Itr implements Iterator<HttpField> { int _cursor; // index of next element to return + int _last=-1; public boolean hasNext() { return _cursor != _size; } - @SuppressWarnings("unchecked") public HttpField next() { int i = _cursor; if (i >= _size) throw new NoSuchElementException(); _cursor = i + 1; - return _fields[i]; + return _fields[_last=i]; } public void remove() { - throw new UnsupportedOperationException(); + if (_last<0) + throw new IllegalStateException(); + + System.arraycopy(_fields,_last+1,_fields,_last,--_size-_last); + _cursor=_last; + _last=-1; } } From 8108a811f06683a17fc81556c85d6b8f5952671b Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 6 Aug 2014 10:15:55 +1000 Subject: [PATCH 202/269] extra HttpFields tests --- .../eclipse/jetty/http/HttpFieldsTest.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 150bfa75687..695b7bb290f 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -29,6 +29,7 @@ import java.nio.ByteBuffer; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; import java.util.Set; @@ -344,9 +345,29 @@ public class HttpFieldsTest assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value1D"); assertEquals(false, e.hasMoreElements()); - } + + @Test + public void testGetQualityValues() throws Exception + { + HttpFields fields = new HttpFields(); + + fields.put("some", "value"); + fields.add("name", "zero;q=0.9,four;q=0.1"); + fields.put("other", "value"); + fields.add("name", "nothing;q=0"); + fields.add("name", "one;q=0.4"); + fields.add("name", "three;x=y;q=0.2;a=b,two;q=0.3"); + + List<String> list = HttpFields.qualityList(fields.getValues("name",",")); + assertEquals("zero",HttpFields.valueParameters(list.get(0),null)); + assertEquals("one",HttpFields.valueParameters(list.get(1),null)); + assertEquals("two",HttpFields.valueParameters(list.get(2),null)); + assertEquals("three",HttpFields.valueParameters(list.get(3),null)); + assertEquals("four",HttpFields.valueParameters(list.get(4),null)); + } + @Test public void testDateFields() throws Exception { From b5971484a57212a39af6f70267ea00a24fdbf100 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 6 Aug 2014 10:50:55 +1000 Subject: [PATCH 203/269] Basic push mechanism skeleton --- .../fcgi/server/HttpTransportOverFCGI.java | 10 +++++ .../org/eclipse/jetty/http/HttpFields.java | 9 ++++ .../http2/server/HttpTransportOverHTTP2.java | 10 +++++ .../jetty/rewrite/handler/RuleContainer.java | 2 +- .../authentication/FormAuthenticator.java | 4 +- .../org/eclipse/jetty/server/Dispatcher.java | 44 ++++++++++++++----- .../eclipse/jetty/server/HttpConnection.java | 10 +++++ .../eclipse/jetty/server/HttpTransport.java | 3 ++ .../org/eclipse/jetty/server/Request.java | 23 ++++++++++ .../eclipse/jetty/server/ResponseTest.java | 5 +++ .../org/eclipse/jetty/servlet/Invoker.java | 2 +- .../eclipse/jetty/servlet/ServletHandler.java | 4 +- .../jetty/servlets/CloseableDoSFilter.java | 2 +- .../server/http/HttpTransportOverSPDY.java | 12 +++++ 14 files changed, 123 insertions(+), 17 deletions(-) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java index 54819e430ed..786f505c258 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java @@ -77,6 +77,16 @@ public class HttpTransportOverFCGI implements HttpTransport flusher.shutdown(); } } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.server.HttpTransport#push(org.eclipse.jetty.http.MetaData.Request) + */ + @Override + public void push(org.eclipse.jetty.http.MetaData.Request request) + { + // LOG.debug("ignore push in {}",this); + } private void commit(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 393b6719f81..a1d1a358bc2 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -71,6 +71,15 @@ public class HttpFields implements Iterable<HttpField> { _fields=new HttpField[capacity]; } + + /** + * Constructor. + */ + public HttpFields(HttpFields fields) + { + _fields=Arrays.copyOf(fields._fields,_fields.length+10); + _size=fields._size; + } public int size() { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 0116485e333..86f37c83e0e 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -86,6 +86,16 @@ public class HttpTransportOverHTTP2 implements HttpTransport } } + /** + * @see org.eclipse.jetty.server.HttpTransport#push(org.eclipse.jetty.http.MetaData.Request) + */ + @Override + public void push(org.eclipse.jetty.http.MetaData.Request request) + { + // TODO implement push + LOG.warn("NOT YET IMPLEMENTED push in {}",this); + } + private void commit(HttpGenerator.ResponseInfo info, boolean endStream, Callback callback) { if (LOG.isDebugEnabled()) diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java index 20d78778d5f..1a4fabf4c8e 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java @@ -227,7 +227,7 @@ public class RuleContainer extends Rule if (rule.isHandling()) { LOG.debug("handling {}",rule); - (request instanceof Request?(Request)request:HttpChannel.getCurrentHttpChannel().getRequest()).setHandled(true); + Request.getBaseRequest(request).setHandled(true); } if (rule.isTerminating()) diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java index 790d544536a..57a1720ea18 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java @@ -289,8 +289,8 @@ public class FormAuthenticator extends LoginAuthenticator LOG.debug("authenticated {}->{}",form_auth,nuri); response.setContentLength(0); - Response base_response = HttpChannel.getCurrentHttpChannel().getResponse(); - Request base_request = HttpChannel.getCurrentHttpChannel().getRequest(); + Request base_request = Request.getBaseRequest(req); + Response base_response = base_request.getResponse(); int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER); base_response.sendRedirect(redirectCode, response.encodeRedirectURL(nuri)); return form_auth; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java index b296ff62aa7..e1b563b381d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java @@ -31,7 +31,11 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.MultiMap; @@ -46,14 +50,14 @@ public class Dispatcher implements RequestDispatcher private final ContextHandler _contextHandler; private final HttpURI _uri; - private final String _pathInfo; + private final String _pathInContext; private final String _named; - public Dispatcher(ContextHandler contextHandler, HttpURI uri, String pathInfo) + public Dispatcher(ContextHandler contextHandler, HttpURI uri, String pathInContext) { _contextHandler=contextHandler; _uri=uri; - _pathInfo=pathInfo; + _pathInContext=pathInContext; _named=null; } @@ -61,7 +65,7 @@ public class Dispatcher implements RequestDispatcher { _contextHandler=contextHandler; _uri=null; - _pathInfo=null; + _pathInContext=null; _named=name; } @@ -79,7 +83,7 @@ public class Dispatcher implements RequestDispatcher @Override public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { - Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(); + Request baseRequest=Request.getBaseRequest(request); if (!(request instanceof HttpServletRequest)) request = new ServletRequestHttpWrapper(request); @@ -104,14 +108,14 @@ public class Dispatcher implements RequestDispatcher attr._requestURI=_uri.getPath(); attr._contextPath=_contextHandler.getContextPath(); attr._servletPath=null; // set by ServletHandler - attr._pathInfo=_pathInfo; + attr._pathInfo=_pathInContext; attr._query=_uri.getQuery(); if (attr._query!=null) baseRequest.mergeQueryParameters(baseRequest.getQueryString(),attr._query, false); baseRequest.setAttributes(attr); - _contextHandler.handle(_pathInfo, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); + _contextHandler.handle(_pathInContext, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); } } finally @@ -126,7 +130,7 @@ public class Dispatcher implements RequestDispatcher protected void forward(ServletRequest request, ServletResponse response, DispatcherType dispatch) throws ServletException, IOException { - Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(); + Request baseRequest=Request.getBaseRequest(request); Response base_response=baseRequest.getResponse(); base_response.resetForForward(); @@ -187,13 +191,13 @@ public class Dispatcher implements RequestDispatcher baseRequest.setContextPath(_contextHandler.getContextPath()); baseRequest.setServletPath(null); - baseRequest.setPathInfo(_pathInfo); + baseRequest.setPathInfo(_pathInContext); if (_uri.getQuery()!=null || old_uri.getQuery()!=null) baseRequest.mergeQueryParameters(old_uri.getQuery(),_uri.getQuery(), true); baseRequest.setAttributes(attr); - _contextHandler.handle(_pathInfo, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); + _contextHandler.handle(_pathInContext, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); if (!baseRequest.getHttpChannelState().isAsync()) commitResponse(response,baseRequest); @@ -212,6 +216,26 @@ public class Dispatcher implements RequestDispatcher baseRequest.setDispatcherType(old_type); } } + + public void push(ServletRequest request) + { + Request baseRequest = Request.getBaseRequest(request); + HttpFields fields = new HttpFields(baseRequest.getHttpFields()); + + String query=baseRequest.getQueryString(); + if (_uri.hasQuery()) + { + if (query==null) + query=_uri.getQuery(); + else + query=query+"&"+_uri.getQuery(); // TODO is this correct semantic? + } + HttpURI uri = new HttpURI(request.getProtocol(),request.getServerName(),request.getServerPort(),_uri.getPath(),baseRequest.getHttpURI().getParam(),query,null); + + MetaData.Request push = new MetaData.Request(HttpMethod.GET.asString(),uri,baseRequest.getHttpVersion(),fields); + + baseRequest.getHttpChannel().getHttpTransport().push(push); + } private void commitResponse(ServletResponse response, Request baseRequest) throws IOException { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 8c5aa76bb05..61fb63d392c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -634,4 +634,14 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http // response is bad either with RST or by abnormal completion of chunked response. getEndPoint().close(); } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.server.HttpTransport#push(org.eclipse.jetty.http.MetaData.Request) + */ + @Override + public void push(org.eclipse.jetty.http.MetaData.Request request) + { + LOG.debug("ignore push in {}",this); + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java index d04a43e9bc3..975c80a67c5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java @@ -21,12 +21,15 @@ package org.eclipse.jetty.server; import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpGenerator; +import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.util.Callback; public interface HttpTransport { void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback); + void push (MetaData.Request request); + void completed(); /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index bcc992e703c..eb38f250bbc 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -52,6 +52,7 @@ import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; +import javax.servlet.ServletRequestWrapper; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; @@ -132,6 +133,28 @@ public class Request implements HttpServletRequest private static final MultiMap<String> NO_PARAMS = new MultiMap<>(); + /* ------------------------------------------------------------ */ + /** + * Obtain the base {@link Request} instance of a {@link ServletRequest}, by + * coercion, unwrapping or thread local. + * @param request The request + * @return the base {@link Request} instance of a {@link ServletRequest}. + */ + public static Request getBaseRequest(ServletRequest request) + { + if (request instanceof Request) + return (Request)request; + + while (request instanceof ServletRequestWrapper) + request=((ServletRequestWrapper)request).getRequest(); + + if (request instanceof Request) + return (Request)request; + + return HttpChannel.getCurrentHttpChannel().getRequest(); + } + + private final HttpChannel _channel; private final List<ServletRequestAttributeListener> _requestAttributeListeners=new ArrayList<>(); private final HttpInput _input; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index d5191f9863c..2bc866863f5 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -91,6 +91,11 @@ public class ResponseTest callback.succeeded(); } + @Override + public void push(org.eclipse.jetty.http.MetaData.Request request) + { + } + @Override public void completed() { diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java index b7f0e748f74..f411078e48a 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java @@ -227,7 +227,7 @@ public class Invoker extends HttpServlet if (holder!=null) { - final Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(); + final Request baseRequest=Request.getBaseRequest(request); holder.handle(baseRequest, new InvokedRequest(request,included,servlet,servlet_path,path_info), response); diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index e650a709fc2..359ee67e451 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -1630,7 +1630,7 @@ public class ServletHandler extends ScopedHandler public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { - final Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(); + final Request baseRequest=Request.getBaseRequest(request); // pass to next filter if (_filterHolder!=null) @@ -1732,7 +1732,7 @@ public class ServletHandler extends ScopedHandler // Call servlet HttpServletRequest srequest = (HttpServletRequest)request; if (_servletHolder == null) - notFound((request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(), srequest, (HttpServletResponse)response); + notFound(Request.getBaseRequest(request), srequest, (HttpServletResponse)response); else { if (LOG.isDebugEnabled()) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CloseableDoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CloseableDoSFilter.java index 5d011221333..157cd0f981a 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CloseableDoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CloseableDoSFilter.java @@ -35,7 +35,7 @@ public class CloseableDoSFilter extends DoSFilter @Override protected void closeConnection(HttpServletRequest request, HttpServletResponse response, Thread thread) { - Request base_request=(request instanceof Request)?(Request)request:HttpChannel.getCurrentHttpChannel().getRequest(); + Request base_request=Request.getBaseRequest(request); base_request.getHttpChannel().getEndPoint().close(); } } diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java index 88b690c0484..682d7541aed 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java @@ -159,6 +159,18 @@ public class HttpTransportOverSPDY implements HttpTransport throw new IllegalStateException("not lastContent, no content and no responseInfo!"); } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.server.HttpTransport#push(org.eclipse.jetty.http.MetaData.Request) + */ + @Override + public void push(org.eclipse.jetty.http.MetaData.Request request) + { + LOG.warn("NOT YET IMPLEMENTED push in {}",this); + } + + private void sendReply(HttpGenerator.ResponseInfo info, Callback callback, boolean close) { Fields headers = new Fields(); From 17f46665df2e0b066b40a3889dbf3f56173e0554 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 6 Aug 2014 21:09:26 +1000 Subject: [PATCH 204/269] preencoded httpfield optimisation --- .../jetty/http/Http1FieldPreEncoder.java | 69 ++++++++ .../org/eclipse/jetty/http/HttpField.java | 36 +++- .../jetty/http/HttpFieldPreEncoder.java | 36 ++++ .../org/eclipse/jetty/http/HttpFields.java | 11 +- .../org/eclipse/jetty/http/HttpGenerator.java | 24 +-- .../org/eclipse/jetty/http/HttpParser.java | 10 +- .../org/eclipse/jetty/http/MimeTypes.java | 6 +- .../jetty/http/PreEncodedHttpField.java | 80 +++++++++ ...org.eclipse.jetty.http.HttpFieldPreEncoder | 1 + .../org/eclipse/jetty/http/HttpFieldTest.java | 16 ++ .../eclipse/jetty/http/HttpFieldsTest.java | 4 - .../jetty/http2/hpack/HpackContext.java | 11 +- .../jetty/http2/hpack/HpackDecoder.java | 6 +- .../jetty/http2/hpack/HpackEncoder.java | 161 ++++++++++-------- .../http2/hpack/HpackFieldPreEncoder.java | 74 ++++++++ ...org.eclipse.jetty.http.HttpFieldPreEncoder | 1 + .../jetty/http2/hpack/HpackContextTest.java | 4 - .../jetty/http2/hpack/HpackDecoderTest.java | 1 - .../jetty/http2/hpack/HpackEncoderTest.java | 2 - .../eclipse/jetty/http2/hpack/HpackTest.java | 15 +- .../http2/server/HttpChannelOverHTTP2.java | 9 +- .../java/org/eclipse/jetty/server/Server.java | 3 +- .../eclipse/jetty/servlet/DefaultServlet.java | 6 +- .../jetty/servlets/AsyncGzipFilter.java | 6 +- .../jetty/servlets/gzip/GzipHttpOutput.java | 4 +- 25 files changed, 449 insertions(+), 147 deletions(-) create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java create mode 100644 jetty-http/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder create mode 100644 jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java create mode 100644 jetty-http2/http2-hpack/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java new file mode 100644 index 00000000000..545611563c4 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java @@ -0,0 +1,69 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http; + +import static java.nio.charset.StandardCharsets.ISO_8859_1; + +import java.util.Arrays; + + +/* ------------------------------------------------------------ */ +/** + */ +public class Http1FieldPreEncoder implements HttpFieldPreEncoder +{ + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion() + */ + @Override + public HttpVersion getHttpVersion() + { + return HttpVersion.HTTP_1_0; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getEncodedField(org.eclipse.jetty.http.HttpHeader, java.lang.String, java.lang.String) + */ + @Override + public byte[] getEncodedField(HttpHeader header, String headerString, String value) + { + if (header!=null) + { + int cbl=header.getBytesColonSpace().length; + byte[] bytes=Arrays.copyOf(header.getBytesColonSpace(), cbl+value.length()+2); + System.arraycopy(value.getBytes(ISO_8859_1),0,bytes,cbl,value.length()); + bytes[bytes.length-2]=(byte)'\r'; + bytes[bytes.length-1]=(byte)'\n'; + return bytes; + } + + byte[] n=headerString.getBytes(ISO_8859_1); + byte[] v=value.getBytes(ISO_8859_1); + byte[] bytes=Arrays.copyOf(n,n.length+2+v.length+2); + bytes[n.length]=(byte)':'; + bytes[n.length]=(byte)' '; + bytes[bytes.length-2]=(byte)'\r'; + bytes[bytes.length-1]=(byte)'\n'; + + return bytes; + } +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index cf3147d0409..8d522379680 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -426,20 +426,30 @@ public class HttpField { final int _int; + public IntValueHttpField(HttpHeader header, String name, String value, int intValue) + { + super(header,name,value); + _int=intValue; + } + public IntValueHttpField(HttpHeader header, String value, int intValue) { - super(header,value); - _int=intValue; + this(header,header.asString(),value,Integer.valueOf(value)); + } + + public IntValueHttpField(HttpHeader header, String name, String value) + { + this(header,name,value,Integer.valueOf(value)); } public IntValueHttpField(HttpHeader header, String value) { - this(header,value,Integer.valueOf(value)); + this(header,header.asString(),value); } public IntValueHttpField(HttpHeader header, int value) { - this(header,Integer.toString(value),value); + this(header,header.asString(),value); } @Override @@ -459,20 +469,30 @@ public class HttpField { final long _long; - public LongValueHttpField(HttpHeader header, String value, long longValue) + public LongValueHttpField(HttpHeader header, String name, String value, long longValue) { - super(header,value); + super(header,name,value); _long=longValue; } + public LongValueHttpField(HttpHeader header, String name, String value) + { + this(header,name,value,Long.valueOf(value)); + } + + public LongValueHttpField(HttpHeader header, String name, long value) + { + this(header,name,Long.toString(value),value); + } + public LongValueHttpField(HttpHeader header, String value) { - this(header,value,StringUtil.toLong(value)); + this(header,header.asString(),value); } public LongValueHttpField(HttpHeader header,long value) { - this(header,Long.toString(value),value); + this(header,header.asString(),value); } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java new file mode 100644 index 00000000000..f05d5e4bad0 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java @@ -0,0 +1,36 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http; + + +/* ------------------------------------------------------------ */ +/** Interface to pre-encode HttpFields. Used by {@link PreEncodedHttpField} + */ +public interface HttpFieldPreEncoder +{ + /* ------------------------------------------------------------ */ + /** The major version this encoder is for. Both HTTP/1.0 and HTTP/1.1 + * use the same field encoding, so the {@link HttpVersion#HTTP_1_0} should + * be return for all HTTP/1.x encodings. + * @return The major version this encoder is for. + */ + HttpVersion getHttpVersion(); + byte[] getEncodedField(HttpHeader header, String headerString, String value); +} \ No newline at end of file diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index a1d1a358bc2..54b2f98202f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.ConcurrentModificationException; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -602,10 +601,14 @@ public class HttpFields implements Iterable<HttpField> if (size() != that.size()) return false; - for (HttpField field : this) + loop: for (HttpField fi : this) { - if (!that.contains(field)) - return false; + for (HttpField fa : that) + { + if (fi.equals(fa)) + continue loop; + } + return false; } return true; } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index 42d0d9c9bee..b67deac5623 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.http; import java.io.IOException; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import org.eclipse.jetty.http.HttpTokens.EndOfContent; @@ -1058,9 +1057,9 @@ public class HttpGenerator public static void putTo(HttpField field, ByteBuffer bufferInFillMode) { - if (field instanceof CachedHttpField) + if (field instanceof PreEncodedHttpField) { - ((CachedHttpField)field).putTo(bufferInFillMode); + ((PreEncodedHttpField)field).putTo(bufferInFillMode,HttpVersion.HTTP_1_0); } else { @@ -1090,23 +1089,4 @@ public class HttpGenerator } BufferUtil.putCRLF(bufferInFillMode); } - - public static class CachedHttpField extends HttpField - { - private final byte[] _bytes; - public CachedHttpField(HttpHeader header,String value) - { - super(header,value); - int cbl=header.getBytesColonSpace().length; - _bytes=Arrays.copyOf(header.getBytesColonSpace(), cbl+value.length()+2); - System.arraycopy(value.getBytes(StandardCharsets.ISO_8859_1),0,_bytes,cbl,value.length()); - _bytes[_bytes.length-2]=(byte)'\r'; - _bytes[_bytes.length-1]=(byte)'\n'; - } - - public void putTo(ByteBuffer bufferInFillMode) - { - bufferInFillMode.put(_bytes); - } - } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index a53ae22e3e4..0fbadad181c 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -183,15 +183,15 @@ public class HttpParser // Add common Content types as fields for (String type : new String[]{"text/plain","text/html","text/xml","text/json","application/json","application/x-www-form-urlencoded"}) { - HttpField field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type); + HttpField field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type); CACHE.put(field); for (String charset : new String[]{"utf-8","iso-8859-1"}) { - CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset)); - CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset)); - CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset.toUpperCase())); - CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset.toUpperCase())); + CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset)); + CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset)); + CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset.toUpperCase())); + CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset.toUpperCase())); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java index dad35e248fc..5778529c874 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java @@ -90,7 +90,7 @@ public class MimeTypes _charset=null; _charsetString=null; _assumedCharset=false; - _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string); + _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); } /* ------------------------------------------------------------ */ @@ -103,7 +103,7 @@ public class MimeTypes _charset=Charset.forName(s.substring(i+9)); _charsetString=_charset==null?null:_charset.toString().toLowerCase(); _assumedCharset=false; - _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string); + _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); } /* ------------------------------------------------------------ */ @@ -115,7 +115,7 @@ public class MimeTypes _charset=cs; _charsetString=_charset==null?null:_charset.toString().toLowerCase(); _assumedCharset=true; - _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string); + _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); } /* ------------------------------------------------------------ */ diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java new file mode 100644 index 00000000000..9e47f50574e --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -0,0 +1,80 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + + +/* ------------------------------------------------------------ */ +/** Pre encoded HttpField. + * <p>A HttpField that will be cached and used many times can be created as + * a {@link PreEncodedHttpField}, which will use the {@link HttpFieldPreEncoder} + * instances discovered by the {@link ServiceLoader} to pre-encode the header + * for each version of HTTP in use. This will save garbage + * and CPU each time the field is encoded into a response. + * </p> + */ +public class PreEncodedHttpField extends HttpField +{ + private final static Logger LOG = Log.getLogger(PreEncodedHttpField.class); + private final static HttpFieldPreEncoder[] __encoders; + + static + { + List<HttpFieldPreEncoder> encoders = new ArrayList<>(); + for (HttpFieldPreEncoder enc : ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader())) + encoders.add(enc); + LOG.debug("HttpField encoders loaded: {}",encoders); + __encoders = encoders.toArray(new HttpFieldPreEncoder[encoders.size()]); + } + + private final byte[][] _encodedField=new byte[2][]; + + public PreEncodedHttpField(HttpHeader header,String name,String value) + { + super(header,name, value); + + for (HttpFieldPreEncoder e:__encoders) + { + _encodedField[e.getHttpVersion()==HttpVersion.HTTP_2?1:0]=e.getEncodedField(header,header.asString(),value); + } + } + + public PreEncodedHttpField(HttpHeader header,String value) + { + this(header,header.asString(),value); + } + + public PreEncodedHttpField(String name,String value) + { + this(null,name,value); + } + + public void putTo(ByteBuffer bufferInFillMode, HttpVersion version) + { + bufferInFillMode.put(_encodedField[version==HttpVersion.HTTP_2?1:0]); + } +} \ No newline at end of file diff --git a/jetty-http/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder b/jetty-http/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder new file mode 100644 index 00000000000..92640bd6b23 --- /dev/null +++ b/jetty-http/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder @@ -0,0 +1 @@ +org.eclipse.jetty.http.Http1FieldPreEncoder \ No newline at end of file diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java index 71ef0835768..06b8c100cd4 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java @@ -22,6 +22,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.BufferUtil; import org.junit.Test; /** @@ -135,4 +138,17 @@ public class HttpFieldTest assertEquals("c",values[2]); } + + @Test + public void testCachedField() + { + PreEncodedHttpField field = new PreEncodedHttpField(HttpHeader.ACCEPT,"something"); + ByteBuffer buf = BufferUtil.allocate(256); + BufferUtil.clearToFill(buf); + field.putTo(buf,HttpVersion.HTTP_1_0); + BufferUtil.flipToFlush(buf,0); + String s=BufferUtil.toString(buf); + + assertEquals("Accept: something\r\n",s); + } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 695b7bb290f..ff2e53d7475 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -26,13 +26,9 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.nio.ByteBuffer; -import java.util.Collections; import java.util.Enumeration; -import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.NoSuchElementException; -import java.util.Set; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 6c929e3fa01..d1cf6172e90 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -28,7 +28,6 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.StringUtil; @@ -231,6 +230,11 @@ public class HpackContext return get(header.asString()); return e; } + + public static Entry getStatic(HttpHeader header) + { + return __headerEntryTable[header.ordinal()]; + } public Entry add(HttpField field) { @@ -420,6 +424,11 @@ public class HpackContext return null; } + public int getSlot() + { + return _slot; + } + public String toString() { return String.format("{%s,%d,%s,%x}",isStatic()?"S":"D",_slot,_field,hashCode()); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 131746908a5..7d24b2ed1da 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -24,8 +24,6 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; @@ -203,7 +201,7 @@ public class HpackDecoder { case C_STATUS: if (indexed) - field = new HttpField.IntValueHttpField(header,value); + field = new HttpField.IntValueHttpField(header,name,value); else field = new HttpField(header,name,value); break; @@ -216,7 +214,7 @@ public class HpackDecoder if ("0".equals(value)) field = CONTENT_LENGTH_0; else - field = new HttpField.LongValueHttpField(header,value); + field = new HttpField.LongValueHttpField(header,name,value); break; default: diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index ee297cc74c7..33c524984e5 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -26,7 +26,9 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.http2.hpack.HpackContext.StaticEntry; import org.eclipse.jetty.io.ByteBufferPool.Lease; @@ -184,8 +186,6 @@ public class HpackEncoder String encoding=null; - // TODO currently we do not check if there is enough space, so we may fail nastily. - // Is there an entry for the field? Entry entry = _context.get(field); if (entry!=null) @@ -209,18 +209,18 @@ public class HpackEncoder else { // Unknown field entry, so we will have to send literally. - final Entry name; final boolean indexed; - final boolean never_index; - final boolean huffman; - final int bits; + // But do we know it's name? HttpHeader header = field.getHeader(); + + // Select encoding strategy if (header==null) { - name = _context.get(field.getName()); - + // Select encoding strategy for unknown header names + Entry name = _context.get(field.getName()); + // has the custom header name been seen before? if (name==null) { @@ -228,95 +228,71 @@ public class HpackEncoder // the first time we have seen a custom name or a custom field. // unless the name is changing, this is worthwhile indexed=true; - never_index=false; - huffman=true; - bits = 6; - buffer.put((byte)0x40); + encodeName(buffer,(byte)0x40,6,field.getName(),null); + encodeValue(buffer,true,field.getValue()); + if (_debug) + encoding="LitHuffNHuffVIdx"; + } else { // known custom name, but unknown value. // This is probably a custom field with changing value, so don't index. indexed=false; - never_index=false; - huffman=true; - bits = 4; - buffer.put((byte)0x00); + encodeName(buffer,(byte)0x00,4,field.getName(),null); + encodeValue(buffer,true,field.getValue()); + if (_debug) + encoding="LitHuffNHuffV!Idx"; } } else { - name = _context.get(header); + // Select encoding strategy for known header names + Entry name = _context.get(header); if (__DO_NOT_INDEX.contains(header)) { // Non indexed field indexed=false; - never_index=__NEVER_INDEX.contains(header); - huffman=!__DO_NOT_HUFFMAN.contains(header); - bits = 4; - buffer.put(never_index?(byte)0x10:(byte)0x00); + boolean never_index=__NEVER_INDEX.contains(header); + boolean huffman=!__DO_NOT_HUFFMAN.contains(header); + encodeName(buffer,never_index?(byte)0x10:(byte)0x00,4,header.asString(),name); + encodeValue(buffer,huffman,field.getValue()); + + if (_debug) + encoding="Lit"+ + ((name==null)?"HuffN":("IdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(4,_context.index(name)))))+ + (huffman?"HuffV":"LitV")+ + (indexed?"Idx":(never_index?"!!Idx":"!Idx")); } else if (header==HttpHeader.CONTENT_LENGTH && field.getValue().length()>1) { // Non indexed content length for non zero value indexed=false; - never_index=false; - huffman=true; - bits = 4; - buffer.put((byte)0x00); + encodeName(buffer,(byte)0x00,4,header.asString(),name); + encodeValue(buffer,true,field.getValue()); + if (_debug) + encoding="LitIdxNS"+(1+NBitInteger.octectsNeeded(4,_context.index(name)))+"HuffV!Idx"; + } + else if (field instanceof PreEncodedHttpField) + { + // Preencoded field + indexed=true; + ((PreEncodedHttpField)field).putTo(buffer,HttpVersion.HTTP_2); + if (_debug) + encoding=((name==null)?"LitHuffN":("LitIdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(6,_context.index(name)))))+ + "HuffVIdx"; } else { // indexed indexed=true; - never_index=false; - huffman=!__DO_NOT_HUFFMAN.contains(header); - bits = 6; - buffer.put((byte)0x40); - } - } - - if (_debug) - { - encoding="Lit"+ - ((name==null)?"HuffN":("IdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(bits,_context.index(name)))))+ - (huffman?"HuffV":"LitV")+ - (indexed?"Idx":(never_index?"!!Idx":"!Idx")); - } - - if (name!=null) - NBitInteger.encode(buffer,bits,_context.index(name)); - else - { - // leave name index bits as 0 - // Encode the name always with lowercase huffman - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(field.getName())); - Huffman.encodeLC(buffer,field.getName()); - } - - // Add the literal value - String value=field.getValue(); - - if (huffman) - { - // huffman literal value - buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeeded(value)); - Huffman.encode(buffer,field.getValue()); - } - else - { - // add literal assuming iso_8859_1 - buffer.put((byte)0x00); - NBitInteger.encode(buffer,7,value.length()); - for (int i=0;i<value.length();i++) - { - char c=value.charAt(i); - if (c<' '|| c>127) - throw new IllegalArgumentException(); - buffer.put((byte)c); + boolean huffman=!__DO_NOT_HUFFMAN.contains(header); + encodeName(buffer,(byte)0x40,6,header.asString(),name); + encodeValue(buffer,huffman,field.getValue()); + if (_debug) + encoding=((name==null)?"LitHuffN":("LitIdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(6,_context.index(name)))))+ + (huffman?"HuffVIdx":"LitVIdx"); } } @@ -333,4 +309,45 @@ public class HpackEncoder LOG.debug("encode {}:'{}' to '{}'",encoding,field,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); } } + + private void encodeName(ByteBuffer buffer, byte mask, int bits, String name, Entry entry) + { + buffer.put(mask); + if (entry==null) + { + // leave name index bits as 0 + // Encode the name always with lowercase huffman + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(name)); + Huffman.encodeLC(buffer,name); + } + else + { + NBitInteger.encode(buffer,bits,_context.index(entry)); + } + } + + private void encodeValue(ByteBuffer buffer, boolean huffman, String value) + { + if (huffman) + { + // huffman literal value + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,Huffman.octetsNeeded(value)); + Huffman.encode(buffer,value); + } + else + { + // add literal assuming iso_8859_1 + buffer.put((byte)0x00); + NBitInteger.encode(buffer,7,value.length()); + for (int i=0;i<value.length();i++) + { + char c=value.charAt(i); + if (c<' '|| c>127) + throw new IllegalArgumentException(); + buffer.put((byte)c); + } + } + } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java new file mode 100644 index 00000000000..330cd2c932a --- /dev/null +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java @@ -0,0 +1,74 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.http2.hpack; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpFieldPreEncoder; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http2.hpack.HpackContext.Entry; +import org.eclipse.jetty.util.BufferUtil; + + +/* ------------------------------------------------------------ */ +/** + */ +public class HpackFieldPreEncoder implements HttpFieldPreEncoder +{ + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion() + */ + @Override + public HttpVersion getHttpVersion() + { + return HttpVersion.HTTP_2; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getEncodedField(org.eclipse.jetty.http.HttpHeader, java.lang.String, java.lang.String) + */ + @Override + public byte[] getEncodedField(HttpHeader header, String name, String value) + { + ByteBuffer buffer = BufferUtil.allocate(name.length()+value.length()+10); + BufferUtil.clearToFill(buffer); + buffer.put((byte)0x40); + Entry entry = header==null?null:HpackContext.getStatic(header); + if (entry==null) + { + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(name)); + Huffman.encodeLC(buffer,name); + } + else + { + NBitInteger.encode(buffer,6,entry.getSlot()); + } + + buffer.put((byte)0x80); + NBitInteger.encode(buffer,7,Huffman.octetsNeeded(value)); + Huffman.encode(buffer,value); + BufferUtil.flipToFlush(buffer,0); + return BufferUtil.toArray(buffer); + } +} diff --git a/jetty-http2/http2-hpack/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder b/jetty-http2/http2-hpack/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder new file mode 100644 index 00000000000..4dca767af12 --- /dev/null +++ b/jetty-http2/http2-hpack/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder @@ -0,0 +1 @@ +org.eclipse.jetty.http2.hpack.HpackFieldPreEncoder \ No newline at end of file diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java index bdf8fcf3cfa..120fc199e6e 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java @@ -24,12 +24,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import java.nio.ByteBuffer; -import java.util.HashSet; -import java.util.Iterator; -import java.util.NoSuchElementException; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index c0f81d58809..af16d2b5da6 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -30,7 +30,6 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.util.TypeUtil; -import org.junit.Ignore; import org.junit.Test; diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index f1bd5a0e1eb..d3b4f883996 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -23,13 +23,11 @@ package org.eclipse.jetty.http2.hpack; import static org.junit.Assert.assertThat; import java.nio.ByteBuffer; -import java.util.HashSet; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; -import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; import org.junit.Assert; diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index ac6a9ac7568..8c256180766 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -24,12 +24,15 @@ import static org.junit.Assert.assertEquals; import java.nio.ByteBuffer; import org.eclipse.jetty.http.BadMessageException; +import org.eclipse.jetty.http.DateGenerator; +import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MetaData.Response; +import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.util.BufferUtil; import org.junit.Assert; import org.junit.Test; @@ -37,6 +40,10 @@ import org.junit.Test; public class HpackTest { + final static HttpField ServerJetty = new PreEncodedHttpField(HttpHeader.SERVER,"jetty"); + final static HttpField XPowerJetty = new PreEncodedHttpField(HttpHeader.X_POWERED_BY,"jetty"); + final static HttpField Date = new PreEncodedHttpField(HttpHeader.DATE,DateGenerator.formatDate(System.currentTimeMillis())); + @Test public void encodeDecodeResponseTest() { @@ -47,7 +54,9 @@ public class HpackTest HttpFields fields0 = new HttpFields(); fields0.add(HttpHeader.CONTENT_TYPE,"text/html"); fields0.add(HttpHeader.CONTENT_LENGTH,"1024"); - fields0.add(HttpHeader.SERVER,"jetty"); + fields0.add(ServerJetty); + fields0.add(XPowerJetty); + fields0.add(Date); fields0.add(HttpHeader.SET_COOKIE,"abcdefghijklmnopqrstuvwxyz"); fields0.add("custom-key","custom-value"); Response original0 = new MetaData.Response(HttpVersion.HTTP_2,200,fields0); @@ -70,7 +79,9 @@ public class HpackTest HttpFields fields1 = new HttpFields(); fields1.add(HttpHeader.CONTENT_TYPE,"text/plain"); fields1.add(HttpHeader.CONTENT_LENGTH,"1234"); - fields1.add(HttpHeader.SERVER,"jetty"); + fields1.add(ServerJetty); + fields0.add(XPowerJetty); + fields0.add(Date); fields1.add("Custom-Key","Other-Value"); Response original1 = new MetaData.Response(HttpVersion.HTTP_2,200,fields1); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 3ee7c939a7e..6b4b114aadf 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.server; import java.io.IOException; import java.nio.ByteBuffer; +import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; @@ -45,9 +46,8 @@ import org.eclipse.jetty.util.log.Logger; public class HttpChannelOverHTTP2 extends HttpChannel { private static final Logger LOG = Log.getLogger(HttpChannelOverHTTP2.class); - private static final HttpField ACCEPT_ENCODING_GZIP = new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip"); - private static final HttpField SERVER_VERSION=new HttpField(HttpHeader.SERVER,HttpConfiguration.SERVER_VERSION); - private static final HttpField POWERED_BY=new HttpField(HttpHeader.X_POWERED_BY,HttpConfiguration.SERVER_VERSION); + private static final HttpField SERVER_VERSION=new PreEncodedHttpField(HttpHeader.SERVER,HttpConfiguration.SERVER_VERSION); + private static final HttpField POWERED_BY=new PreEncodedHttpField(HttpHeader.X_POWERED_BY,HttpConfiguration.SERVER_VERSION); private final Stream stream; // TODO recycle channel for new Stream? private boolean _expect100Continue = false; @@ -86,11 +86,8 @@ public class HttpChannelOverHTTP2 extends HttpChannel onRequest(request); - if (frame.isEndStream()) - { onRequestComplete(); - } if (LOG.isDebugEnabled()) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index e207466cd4b..370259f6552 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -38,6 +38,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.DateGenerator; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpGenerator; @@ -299,7 +300,7 @@ public class Server extends HandlerWrapper implements Attributes df = _dateField; if (df==null || df._seconds!=seconds) { - HttpField field=new HttpGenerator.CachedHttpField(HttpHeader.DATE,DateGenerator.formatDate(now)); + HttpField field=new PreEncodedHttpField(HttpHeader.DATE,DateGenerator.formatDate(now)); _dateField=new DateField(seconds,field); return field; } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java index 29bcb57f117..d6c2a341f0f 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java @@ -39,10 +39,10 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.HttpContent; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpGenerator.CachedHttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.MimeTypes; @@ -144,7 +144,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory private static final long serialVersionUID = 4930458713846881193L; - private static final CachedHttpField ACCEPT_RANGES = new CachedHttpField(HttpHeader.ACCEPT_RANGES, "bytes"); + private static final PreEncodedHttpField ACCEPT_RANGES = new PreEncodedHttpField(HttpHeader.ACCEPT_RANGES, "bytes"); private ServletContext _servletContext; private ContextHandler _contextHandler; @@ -241,7 +241,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory String cc=getInitParameter("cacheControl"); if (cc!=null) - _cacheControl=new CachedHttpField(HttpHeader.CACHE_CONTROL, cc); + _cacheControl=new PreEncodedHttpField(HttpHeader.CACHE_CONTROL, cc); String resourceCache = getInitParameter("resourceCache"); int max_cache_size=getInitInt("maxCacheSize", -2); diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java index febeae01166..9097aa47b50 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java @@ -37,9 +37,9 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; @@ -152,7 +152,7 @@ public class AsyncGzipFilter extends UserAgentFilter implements GzipFactory protected Set<Pattern> _excludedAgentPatterns; protected Set<String> _excludedPaths; protected Set<Pattern> _excludedPathPatterns; - protected HttpField _vary=new HttpGenerator.CachedHttpField(HttpHeader.VARY,HttpHeader.ACCEPT_ENCODING+", "+HttpHeader.USER_AGENT); + protected HttpField _vary=new PreEncodedHttpField(HttpHeader.VARY,HttpHeader.ACCEPT_ENCODING+", "+HttpHeader.USER_AGENT); /* ------------------------------------------------------------ */ /** @@ -278,7 +278,7 @@ public class AsyncGzipFilter extends UserAgentFilter implements GzipFactory tmp=filterConfig.getInitParameter("vary"); if (tmp!=null) - _vary=new HttpGenerator.CachedHttpField(HttpHeader.VARY,tmp); + _vary=new PreEncodedHttpField(HttpHeader.VARY,tmp); LOG.debug("{} vary={}",this,_vary); } diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java index 37a6bc111a2..63cd39860e1 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java @@ -24,8 +24,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.zip.CRC32; import java.util.zip.Deflater; +import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.server.HttpChannel; @@ -41,7 +41,7 @@ import org.eclipse.jetty.util.log.Logger; public class GzipHttpOutput extends HttpOutput { public static Logger LOG = Log.getLogger(GzipHttpOutput.class); - private final static HttpGenerator.CachedHttpField CONTENT_ENCODING_GZIP=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_ENCODING,"gzip"); + private final static PreEncodedHttpField CONTENT_ENCODING_GZIP=new PreEncodedHttpField(HttpHeader.CONTENT_ENCODING,"gzip"); private final static byte[] GZIP_HEADER = new byte[] { (byte)0x1f, (byte)0x8b, Deflater.DEFLATED, 0, 0, 0, 0, 0, 0, 0 }; private enum GZState { NOT_COMPRESSING, MIGHT_COMPRESS, COMMITTING, COMPRESSING, FINISHED}; From 015c34d865dc291bb1ea51999aa835288956463a Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 6 Aug 2014 15:21:33 +0200 Subject: [PATCH 205/269] Fixed handling of the close state in case it's already closed. --- .../main/java/org/eclipse/jetty/util/IteratingCallback.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java index 960c3eb9749..b11a18882df 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java @@ -382,6 +382,10 @@ public abstract class IteratingCallback implements Callback return; break; } + case CLOSED: + { + return; + } default: { if (_state.compareAndSet(current, State.CLOSED)) From 2cd53831c035fd9f82bd5604df40c95bc7cf1073 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 6 Aug 2014 15:39:29 +0200 Subject: [PATCH 206/269] Refactored onReadTimeout() to parent class. --- .../http2/client/HTTP2ClientConnectionFactory.java | 10 ---------- .../java/org/eclipse/jetty/http2/HTTP2Connection.java | 9 +++++++++ .../server/AbstractHTTP2ServerConnectionFactory.java | 10 ---------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index f03df621109..a3c6ac10a45 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -23,7 +23,6 @@ import java.nio.ByteBuffer; import java.util.Map; import java.util.concurrent.Executor; -import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.HTTP2Session; @@ -92,15 +91,6 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory client.removeSession(getSession()); } - @Override - protected boolean onReadTimeout() - { - if (LOG.isDebugEnabled()) - LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); - getSession().close(ErrorCodes.NO_ERROR, "idle_timeout", closeCallback); - return false; - } - @Override public void succeeded() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index 0511ecf264b..4115c760018 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -122,4 +122,13 @@ public class HTTP2Connection extends AbstractConnection if (!endPoint.isOutputShutdown()) session.shutdown(); } + + @Override + protected boolean onReadTimeout() + { + if (LOG.isDebugEnabled()) + LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); + getSession().close(ErrorCodes.NO_ERROR, "idle_timeout", closeCallback); + return false; + } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 023acb263c4..17eba76fd0a 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.http2.server; import java.util.concurrent.Executor; -import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.ISession; @@ -112,15 +111,6 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne notifyConnect(getSession()); } - @Override - protected boolean onReadTimeout() - { - if (LOG.isDebugEnabled()) - LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); - getSession().close(ErrorCodes.NO_ERROR, "idle_timeout", closeCallback); - return false; - } - private void notifyConnect(ISession session) { try From abd139cc1be6464d97586ac995311d06ba081ba8 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 6 Aug 2014 15:42:36 +0200 Subject: [PATCH 207/269] Reworked flow control implementation. Splitted HTTP2Flusher out of HTTP2Session. Flow control window updates are now processed by the flusher, so that it is the only component that handles window updates. In the process of this refactoring, HTTP2Flusher was refactored out of HTTP2Session. --- .../jetty/http2/client/FlowControlTest.java | 69 +++ .../org/eclipse/jetty/http2/FlowControl.java | 8 +- .../eclipse/jetty/http2/HTTP2FlowControl.java | 43 +- .../org/eclipse/jetty/http2/HTTP2Flusher.java | 391 ++++++++++++++++ .../org/eclipse/jetty/http2/HTTP2Session.java | 426 ++++-------------- .../org/eclipse/jetty/http2/ISession.java | 5 +- 6 files changed, 584 insertions(+), 358 deletions(-) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index def59646e98..dabd221d952 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -462,4 +462,73 @@ public class FlowControlTest extends AbstractTest Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); Assert.assertArrayEquals(data, bytes); } + + @Test + public void testServerTwoDataFramesWithStalledSession() throws Exception + { + // Frames in queue = DATA1, DATA2. + // Server writes part of DATA1, then stalls. + // A window update unstalls the session, verify that the data is correctly sent. + + Random random = new Random(); + final byte[] chunk1 = new byte[1024]; + random.nextBytes(chunk1); + final byte[] chunk2 = new byte[1024]; + random.nextBytes(chunk2); + + final AtomicReference<CountDownLatch> settingsLatch = new AtomicReference<>(new CountDownLatch(1)); + final CountDownLatch dataLatch = new CountDownLatch(1); + startServer(new ServerSessionListener.Adapter() + { + @Override + public void onSettings(Session session, SettingsFrame frame) + { + settingsLatch.get().countDown(); + } + + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk1), false), Callback.Adapter.INSTANCE); + stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk2), true), Callback.Adapter.INSTANCE); + dataLatch.countDown(); + return null; + } + }); + + Session session = newClient(new Session.Listener.Adapter()); + Map<Integer, Integer> settings = new HashMap<>(); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, 0); + session.settings(new SettingsFrame(settings, false), Callback.Adapter.INSTANCE); + Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS)); + + byte[] content = new byte[chunk1.length + chunk2.length]; + final ByteBuffer buffer = ByteBuffer.wrap(content); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, true); + final CountDownLatch responseLatch = new CountDownLatch(1); + session.newStream(requestFrame, new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + buffer.put(frame.getData()); + callback.succeeded(); + if (frame.isEndStream()) + responseLatch.countDown(); + } + }); + Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); + + // Now we have the 2 DATA frames queued in the server. + + // Partially unstall the first DATA frame. + settingsLatch.set(new CountDownLatch(1)); + settings.clear(); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, chunk1.length / 2); + session.settings(new SettingsFrame(settings, false), Callback.Adapter.INSTANCE); + Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS)); + + Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java index 40618addffd..d4087435b33 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java @@ -30,11 +30,13 @@ public interface FlowControl public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame); - public void onDataReceived(ISession session, IStream stream, int length); + public void onDataReceived(IStream stream, int length); - public void onDataConsumed(ISession session, IStream stream, int length); + public void onDataConsumed(IStream stream, int length); - public void onDataSent(ISession session, IStream stream, int length); + public void onDataSending(IStream stream, int length); + + public void onDataSent(IStream stream, int length); public void onSessionStalled(ISession session); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index 9111a1f17ad..efa5e5545a8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -52,21 +52,14 @@ public class HTTP2FlowControl implements FlowControl { int windowSize = this.initialWindowSize; this.initialWindowSize = initialWindowSize; - int delta = initialWindowSize - windowSize; - // Update the sessions's window size. - int oldSize = session.updateWindowSize(delta); - if (LOG.isDebugEnabled()) - LOG.debug("Updated session initial window {} -> {} for {}", oldSize, oldSize + delta, session); + // Update the session's window size. + session.onUpdateWindowSize(null, new WindowUpdateFrame(0, delta)); // Update the streams' window size. for (Stream stream : session.getStreams()) - { - oldSize = ((IStream)stream).updateWindowSize(delta); - if (LOG.isDebugEnabled()) - LOG.debug("Updated stream initial window {} -> {} for {}", oldSize, oldSize + delta, stream); - } + session.onUpdateWindowSize((IStream)stream, new WindowUpdateFrame(stream.getId(), delta)); } @Override @@ -92,12 +85,12 @@ public class HTTP2FlowControl implements FlowControl } @Override - public void onDataReceived(ISession session, IStream stream, int length) + public void onDataReceived(IStream stream, int length) { } @Override - public void onDataConsumed(ISession session, IStream stream, int length) + public void onDataConsumed(IStream stream, int length) { // This is the algorithm for flow control. // This method is called when a whole flow controlled frame has been consumed. @@ -107,28 +100,32 @@ public class HTTP2FlowControl implements FlowControl if (LOG.isDebugEnabled()) LOG.debug("Data consumed, increasing window by {} for {}", length, stream); // Negative streamId allow for generation of bytes for both stream and session - int streamId = stream != null ? -stream.getId() : 0; - WindowUpdateFrame frame = new WindowUpdateFrame(streamId, length); - session.control(stream, frame, Callback.Adapter.INSTANCE); + WindowUpdateFrame frame = new WindowUpdateFrame(-stream.getId(), length); + stream.getSession().control(stream, frame, Callback.Adapter.INSTANCE); } @Override - public void onDataSent(ISession session, IStream stream, int length) + public void onDataSending(IStream stream, int length) { if (length == 0) return; if (LOG.isDebugEnabled()) - LOG.debug("Data sent, decreasing window by {}", length); + LOG.debug("Data sending, decreasing windows by {}", length); + + ISession session = stream.getSession(); int oldSize = session.updateWindowSize(-length); if (LOG.isDebugEnabled()) LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize - length, session); - if (stream != null) - { - oldSize = stream.updateWindowSize(-length); - if (LOG.isDebugEnabled()) - LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize - length, stream); - } + + oldSize = stream.updateWindowSize(-length); + if (LOG.isDebugEnabled()) + LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize - length, stream); + } + + @Override + public void onDataSent(IStream stream, int length) + { } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java new file mode 100644 index 00000000000..fdbb23a773e --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java @@ -0,0 +1,391 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +import java.io.EOFException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.ArrayQueue; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.IteratingCallback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class HTTP2Flusher extends IteratingCallback +{ + private static final Logger LOG = Log.getLogger(HTTP2Flusher.class); + + private final Deque<WindowEntry> windows = new ArrayDeque<>(); + private final ArrayQueue<Entry> frames = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH, this); + private final Map<IStream, Integer> streams = new HashMap<>(); + private final List<Entry> reset = new ArrayList<>(); + private final HTTP2Session session; + private final ByteBufferPool.Lease lease; + private final List<Entry> active; + private final Queue<Entry> complete; + + public HTTP2Flusher(HTTP2Session session) + { + this.session = session; + this.lease = new ByteBufferPool.Lease(session.getGenerator().getByteBufferPool()); + this.active = new ArrayList<>(); + this.complete = new ArrayDeque<>(); + } + + public void window(IStream stream, WindowUpdateFrame frame) + { + synchronized (this) + { + if (!isClosed()) + { + windows.offer(new WindowEntry(stream, frame)); + // Flush stalled data. + iterate(); + } + } + } + + public void prepend(Entry entry) + { + boolean fail = false; + synchronized (this) + { + if (isClosed()) + { + fail = true; + } + else + { + frames.add(0, entry); + if (LOG.isDebugEnabled()) + LOG.debug("Prepended {}, frames={}", entry, frames.size()); + } + } + if (fail) + closed(entry, new ClosedChannelException()); + } + + public void append(Entry entry) + { + boolean fail = false; + synchronized (this) + { + if (isClosed()) + { + fail = true; + } + else + { + frames.offer(entry); + if (LOG.isDebugEnabled()) + LOG.debug("Appended {}, frames={}", entry, frames.size()); + } + } + if (fail) + closed(entry, new ClosedChannelException()); + } + + public int getQueueSize() + { + synchronized (this) + { + return frames.size(); + } + } + + @Override + protected Action process() throws Exception + { + if (LOG.isDebugEnabled()) + LOG.debug("Flushing {}", session); + + synchronized (this) + { + // First thing, update the window sizes, so we can + // reason about the frames to remove from the queue. + while (!windows.isEmpty()) + { + WindowEntry entry = windows.poll(); + entry.perform(); + } + + // Now the window sizes cannot change. + // Window updates that happen concurrently will + // be queued and processed on the next iteration. + int sessionWindow = session.getWindowSize(); + + int index = 0; + int size = frames.size(); + while (index < size) + { + Entry entry = frames.get(index); + + // We need to compute how many frames fit in the windows. + + IStream stream = entry.stream; + int remaining = entry.dataRemaining(); + if (remaining > 0) + { + if (sessionWindow <= 0) + { + session.getFlowControl().onSessionStalled(session); + ++index; + // There may be *non* flow controlled frames to send. + continue; + } + + // The stream may have a smaller window than the session. + Integer streamWindow = streams.get(stream); + if (streamWindow == null) + { + streamWindow = stream.getWindowSize(); + streams.put(stream, streamWindow); + } + + // Is it a frame belonging to an already stalled stream ? + if (streamWindow <= 0) + { + session.getFlowControl().onStreamStalled(stream); + ++index; + // There may be *non* flow controlled frames to send. + continue; + } + } + + // We will be possibly writing this + // frame, remove it from the queue. + if (index == 0) + frames.pollUnsafe(); + else + frames.remove(index); + --size; + + // If the stream has been reset, don't send the frame. + if (stream != null && stream.isReset()) + { + reset.add(entry); + continue; + } + + // Reduce the flow control windows. + if (remaining > 0) + { + sessionWindow -= remaining; + streams.put(stream, streams.get(stream) - remaining); + } + + // The frame will be written. + active.add(entry); + + if (LOG.isDebugEnabled()) + LOG.debug("Gathered {}", entry); + } + streams.clear(); + } + + // Perform resets outside the sync block. + for (int i = 0; i < reset.size(); ++i) + { + Entry entry = reset.get(i); + entry.reset(); + } + reset.clear(); + + if (active.isEmpty()) + { + if (isClosed()) + terminate(new ClosedChannelException()); + + if (LOG.isDebugEnabled()) + LOG.debug("Flushed {}", session); + + return Action.IDLE; + } + + for (int i = 0; i < active.size(); ++i) + { + Entry entry = active.get(i); + Throwable failure = entry.generate(lease); + if (failure != null) + { + // Failure to generate the entry is catastrophic. + failed(failure); + return Action.SUCCEEDED; + } + } + + List<ByteBuffer> byteBuffers = lease.getByteBuffers(); + if (LOG.isDebugEnabled()) + LOG.debug("Writing {} buffers ({} bytes) for {} frames {}", byteBuffers.size(), lease.getTotalLength(), active.size(), active); + session.getEndPoint().write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()])); + return Action.SCHEDULED; + } + + @Override + public void succeeded() + { + lease.recycle(); + + // Transfer active items to avoid reentrancy. + for (int i = 0; i < active.size(); ++i) + complete.add(active.get(i)); + active.clear(); + + if (LOG.isDebugEnabled()) + LOG.debug("Written {} frames for {}", complete.size(), complete); + + // Drain the frames one by one to avoid reentrancy. + while (!complete.isEmpty()) + { + Entry entry = complete.poll(); + entry.succeeded(); + } + + super.succeeded(); + } + + @Override + protected void onCompleteSuccess() + { + throw new IllegalStateException(); + } + + @Override + protected void onCompleteFailure(Throwable x) + { + if (LOG.isDebugEnabled()) + LOG.debug(x); + + lease.recycle(); + + // Transfer active items to avoid reentrancy. + for (int i = 0; i < active.size(); ++i) + complete.add(active.get(i)); + active.clear(); + + // Drain the frames one by one to avoid reentrancy. + while (!complete.isEmpty()) + { + Entry entry = complete.poll(); + entry.failed(x); + } + + terminate(x); + } + + @Override + public void close() + { + super.close(); + iterate(); + } + + private void terminate(Throwable x) + { + Queue<Entry> queued; + synchronized (this) + { + queued = new ArrayDeque<>(frames); + frames.clear(); + } + + if (LOG.isDebugEnabled()) + LOG.debug("Terminating, queued={}", queued.size()); + + for (Entry entry : queued) + closed(entry, x); + + session.disconnect(); + } + + private void closed(Entry entry, Throwable failure) + { + entry.failed(failure); + } + + public static abstract class Entry implements Callback + { + protected final Frame frame; + protected final IStream stream; + protected final Callback callback; + + protected Entry(Frame frame, IStream stream, Callback callback) + { + this.frame = frame; + this.stream = stream; + this.callback = callback; + } + + public int dataRemaining() + { + return 0; + } + + public Throwable generate(ByteBufferPool.Lease lease) + { + return null; + } + + public void reset() + { + failed(new EOFException("reset")); + } + + @Override + public void failed(Throwable x) + { + callback.failed(x); + } + + @Override + public String toString() + { + return frame.toString(); + } + } + + private class WindowEntry + { + private final IStream stream; + private final WindowUpdateFrame frame; + + public WindowEntry(IStream stream, WindowUpdateFrame frame) + { + this.stream = stream; + this.frame = frame; + } + + public void perform() + { + FlowControl flowControl = session.getFlowControl(); + flowControl.onWindowUpdate(session, stream, frame); + } + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index e784127db36..1f763d89b87 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -18,18 +18,13 @@ package org.eclipse.jetty.http2; -import java.io.EOFException; import java.nio.ByteBuffer; -import java.nio.channels.ClosedChannelException; import java.nio.charset.StandardCharsets; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -52,11 +47,9 @@ import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.util.ArrayQueue; import org.eclipse.jetty.util.Atomics; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -86,7 +79,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final Generator generator; private final Listener listener; private final FlowControl flowControl; - private final Flusher flusher; + private final HTTP2Flusher flusher; private int maxLocalStreams; private int maxRemoteStreams; @@ -97,13 +90,18 @@ public abstract class HTTP2Session implements ISession, Parser.Listener this.generator = generator; this.listener = listener; this.flowControl = flowControl; - this.flusher = new Flusher(4); + this.flusher = new HTTP2Flusher(this); this.maxLocalStreams = maxStreams; this.maxRemoteStreams = maxStreams; this.streamIds.set(initialStreamId); this.windowSize.set(flowControl.getInitialWindowSize()); } + public FlowControl getFlowControl() + { + return flowControl; + } + public int getMaxRemoteStreams() { return maxRemoteStreams; @@ -114,6 +112,11 @@ public abstract class HTTP2Session implements ISession, Parser.Listener this.maxRemoteStreams = maxRemoteStreams; } + public EndPoint getEndPoint() + { + return endPoint; + } + public Generator getGenerator() { return generator; @@ -131,13 +134,13 @@ public abstract class HTTP2Session implements ISession, Parser.Listener stream.updateClose(frame.isEndStream(), false); // The flow control length includes the padding bytes. final int flowControlLength = frame.remaining() + frame.padding(); - flowControl.onDataReceived(this, stream, flowControlLength); + flowControl.onDataReceived(stream, flowControlLength); boolean result = stream.process(frame, new Callback.Adapter() { @Override public void succeeded() { - flowControl.onDataConsumed(HTTP2Session.this, stream, flowControlLength); + flowControl.onDataConsumed(stream, flowControlLength); } }); if (stream.isClosed()) @@ -263,7 +266,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } flusher.close(); - disconnect(); notifyClose(this, frame); @@ -291,13 +293,16 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (LOG.isDebugEnabled()) LOG.debug("Received {}", frame); int streamId = frame.getStreamId(); - IStream stream = null; if (streamId > 0) - stream = getStream(streamId); - flowControl.onWindowUpdate(this, stream, frame); - - // Flush stalled data. - flusher.iterate(); + { + IStream stream = getStream(streamId); + if (stream != null) + onUpdateWindowSize(stream, frame); + } + else + { + onUpdateWindowSize(null, frame); + } return false; } @@ -325,7 +330,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener stream.updateClose(frame.isEndStream(), true); stream.setListener(listener); - FlusherEntry entry = new FlusherEntry(stream, frame, new PromiseCallback<>(promise, stream)); + ControlEntry entry = new ControlEntry(frame, stream, new PromiseCallback<>(promise, stream)); flusher.append(entry); } // Iterate outside the synchronized block. @@ -373,17 +378,17 @@ public abstract class HTTP2Session implements ISession, Parser.Listener public void control(IStream stream, Frame frame, Callback callback) { // We want to generate as late as possible to allow re-prioritization. - frame(new FlusherEntry(stream, frame, callback)); + frame(new ControlEntry(frame, stream, callback)); } @Override public void data(IStream stream, DataFrame frame, Callback callback) { // We want to generate as late as possible to allow re-prioritization. - frame(new DataFlusherEntry(stream, frame, callback)); + frame(new DataEntry(frame, stream, callback)); } - private void frame(FlusherEntry entry) + private void frame(HTTP2Flusher.Entry entry) { if (LOG.isDebugEnabled()) LOG.debug("Sending {}", entry.frame); @@ -494,6 +499,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return result; } + @Override public IStream getStream(int streamId) { return streams.get(streamId); @@ -510,17 +516,30 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return windowSize.getAndAdd(delta); } + @Override + public void onUpdateWindowSize(IStream stream, WindowUpdateFrame frame) + { + // WindowUpdateFrames arrive concurrently with writes. + // Increasing (or reducing) the window size concurrently + // with writes requires coordination with the flusher, that + // decides how many frames to write depending on the available + // window sizes. If the window sizes vary concurrently, the + // flusher may take non-optimal or wrong decisions. + // Here, we "queue" window updates to the flusher, so it will + // be the only component responsible for window updates, for + // both increments and reductions. + flusher.window(stream, frame); + } + @Override public void shutdown() { if (LOG.isDebugEnabled()) LOG.debug("Shutting down"); - - // Append a fake FlusherEntry that disconnects when the queue is drained. - flusher.append(new ShutdownFlusherEntry()); - flusher.iterate(); + flusher.close(); } + @Override public void disconnect() { if (LOG.isDebugEnabled()) @@ -606,265 +625,30 @@ public abstract class HTTP2Session implements ISession, Parser.Listener hashCode(), flusher.getQueueSize(), windowSize, streams.size()); } - private class Flusher extends IteratingCallback + private class ControlEntry extends HTTP2Flusher.Entry { - private final ArrayQueue<FlusherEntry> queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH); - private final Map<IStream, Integer> streams = new HashMap<>(); - private final List<FlusherEntry> reset = new ArrayList<>(); - private final ByteBufferPool.Lease lease = new ByteBufferPool.Lease(generator.getByteBufferPool()); - private final int maxGather; - private final List<FlusherEntry> active; - private final Queue<FlusherEntry> complete; - - private Flusher(int maxGather) + private ControlEntry(Frame frame, IStream stream, Callback callback) { - this.maxGather = maxGather; - this.active = new ArrayList<>(maxGather); - this.complete = new ArrayDeque<>(maxGather); + super(frame, stream, callback); } - private void append(FlusherEntry entry) - { - boolean fail = false; - synchronized (queue) - { - if (isClosed()) - fail = true; - else - queue.offer(entry); - if (LOG.isDebugEnabled()) - LOG.debug("Appended {}, queue={}", entry, queue.size()); - } - if (fail) - closed(entry); - } - - private void prepend(FlusherEntry entry) - { - boolean fail = false; - synchronized (queue) - { - if (isClosed()) - fail = true; - else - queue.add(0, entry); - } - if (fail) - closed(entry); - } - - private int getQueueSize() - { - synchronized (queue) - { - return queue.size(); - } - } - - @Override - protected Action process() throws Exception - { - synchronized (queue) - { - // The session window size may vary concurrently upon receipt of - // WINDOW_UPDATE or SETTINGS so we read it here and not in the loop. - // The stream window size is read in the loop, but it's always - // capped by the session window size. - int sessionWindow = getWindowSize(); - int nonStalledIndex = 0; - int size = queue.size(); - while (nonStalledIndex < size) - { - FlusherEntry entry = queue.get(nonStalledIndex); - IStream stream = entry.stream; - int remaining = 0; - if (entry.frame instanceof DataFrame) - { - DataFrame dataFrame = (DataFrame)entry.frame; - remaining = dataFrame.remaining(); - if (remaining > 0) - { - // Is the session stalled ? - if (sessionWindow <= 0) - { - flowControl.onSessionStalled(HTTP2Session.this); - ++nonStalledIndex; - // There may be *non* flow controlled frames to send. - continue; - } - - // The stream may have a smaller window than the session. - Integer streamWindow = streams.get(stream); - if (streamWindow == null) - { - streamWindow = stream.getWindowSize(); - streams.put(stream, streamWindow); - } - - // Is it a frame belonging to an already stalled stream ? - if (streamWindow <= 0) - { - flowControl.onStreamStalled(stream); - ++nonStalledIndex; - // There may be *non* flow controlled frames to send. - continue; - } - } - } - - // We will be possibly writing this frame. - queue.remove(nonStalledIndex); - --size; - - // If the stream has been reset, don't send flow controlled frames. - if (stream != null && stream.isReset() && remaining > 0) - { - reset.add(entry); - continue; - } - - // Reduce the flow control windows. - sessionWindow -= remaining; - if (stream != null && remaining > 0) - streams.put(stream, streams.get(stream) - remaining); - - active.add(entry); - if (active.size() == maxGather) - break; - } - streams.clear(); - } - - for (int i = 0; i < reset.size(); ++i) - { - FlusherEntry entry = reset.get(i); - entry.reset(); - } - reset.clear(); - - if (active.isEmpty()) - return Action.IDLE; - - for (int i = 0; i < active.size(); ++i) - { - FlusherEntry entry = active.get(i); - entry.generate(lease); - } - - List<ByteBuffer> byteBuffers = lease.getByteBuffers(); - if (LOG.isDebugEnabled()) - LOG.debug("Writing {} buffers ({} bytes) for {} frames {}", byteBuffers.size(), lease.getTotalLength(), active.size(), active); - endPoint.write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()])); - return Action.SCHEDULED; - } - - @Override - public void succeeded() - { - lease.recycle(); - - // Transfer active items to avoid reentrancy. - for (int i = 0; i < active.size(); ++i) - complete.add(active.get(i)); - active.clear(); - - if (LOG.isDebugEnabled()) - LOG.debug("Written {} frames for {}", complete.size(), complete); - - // Drain the queue one by one to avoid reentrancy. - while (!complete.isEmpty()) - { - FlusherEntry entry = complete.poll(); - entry.succeeded(); - } - - super.succeeded(); - } - - @Override - protected void onCompleteSuccess() - { - throw new IllegalStateException(); - } - - @Override - protected void onCompleteFailure(Throwable x) - { - if (LOG.isDebugEnabled()) - LOG.debug(x); - - lease.recycle(); - - // Transfer active items to avoid reentrancy. - for (int i = 0; i < active.size(); ++i) - complete.add(active.get(i)); - active.clear(); - - // Drain the queue one by one to avoid reentrancy. - while (!complete.isEmpty()) - { - FlusherEntry entry = complete.poll(); - entry.failed(x); - } - } - - public void close() - { - super.close(); - - Queue<FlusherEntry> queued; - synchronized (queue) - { - queued = new ArrayDeque<>(queue); - queue.clear(); - } - - if (LOG.isDebugEnabled()) - LOG.debug("Closing, queued={}", queued.size()); - - for (FlusherEntry item : queued) - closed(item); - } - - protected void closed(FlusherEntry item) - { - item.failed(new ClosedChannelException()); - } - } - - private class FlusherEntry implements Callback - { - protected final IStream stream; - protected final Frame frame; - protected final Callback callback; - - private FlusherEntry(IStream stream, Frame frame, Callback callback) - { - this.stream = stream; - this.frame = frame; - this.callback = callback; - } - - public void generate(ByteBufferPool.Lease lease) + public Throwable generate(ByteBufferPool.Lease lease) { try { generator.control(lease, frame); if (LOG.isDebugEnabled()) LOG.debug("Generated {}", frame); + return null; } catch (Throwable x) { - LOG.debug("Frame generation failure", x); - failed(x); + if (LOG.isDebugEnabled()) + LOG.debug("Failure generating frame " + frame, x); + return x; } } - public void reset() - { - callback.failed(new EOFException("reset")); - } - @Override public void succeeded() { @@ -888,51 +672,64 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } callback.succeeded(); } - - @Override - public void failed(Throwable x) - { - if (stream != null) - stream.close(); - close(ErrorCodes.INTERNAL_ERROR, "generator_error", Adapter.INSTANCE); - callback.failed(x); - } - - @Override - public String toString() - { - return frame.toString(); - } } - private class DataFlusherEntry extends FlusherEntry + private class DataEntry extends HTTP2Flusher.Entry { private int length; - private DataFlusherEntry(IStream stream, DataFrame frame, Callback callback) + private DataEntry(DataFrame frame, IStream stream, Callback callback) { - super(stream, frame, callback); + super(frame, stream, callback); } - public void generate(ByteBufferPool.Lease lease) + @Override + public int dataRemaining() { - DataFrame dataFrame = (DataFrame)frame; - int flowControlLength = dataFrame.remaining() + dataFrame.padding(); + // We don't do any padding, so the flow control length is + // always the data remaining. This simplifies the handling + // of data frames that cannot be completely written due to + // the flow control window exhausting, since in that case + // we would have to count the padding only once. + return ((DataFrame)frame).remaining(); + } - int streamWindowSize = stream.getWindowSize(); - int sessionWindowSize = getWindowSize(); - int windowSize = Math.min(streamWindowSize, sessionWindowSize); + public Throwable generate(ByteBufferPool.Lease lease) + { + try + { + int flowControlLength = dataRemaining(); - length = Math.min(flowControlLength, windowSize); - if (LOG.isDebugEnabled()) - LOG.debug("Generated {}, maxLength={}", dataFrame, length); - generator.data(lease, dataFrame, length); + int sessionWindowSize = getWindowSize(); + if (sessionWindowSize < 0) + throw new IllegalStateException(); + + int streamWindowSize = stream.getWindowSize(); + if (streamWindowSize < 0) + throw new IllegalStateException(); + + int windowSize = Math.min(streamWindowSize, sessionWindowSize); + + int length = this.length = Math.min(flowControlLength, windowSize); + if (LOG.isDebugEnabled()) + LOG.debug("Generated {}, length/window={}/{}", frame, length, windowSize); + + generator.data(lease, (DataFrame)frame, length); + flowControl.onDataSending(stream, length); + return null; + } + catch (Throwable x) + { + if (LOG.isDebugEnabled()) + LOG.debug("Failure generating frame " + frame, x); + return x; + } } @Override public void succeeded() { - flowControl.onDataSent(HTTP2Session.this, stream, length); + flowControl.onDataSent(stream, length); // Do we have more to send ? DataFrame dataFrame = (DataFrame)frame; if (dataFrame.remaining() > 0) @@ -954,39 +751,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } - private class ShutdownFlusherEntry extends FlusherEntry - { - public ShutdownFlusherEntry() - { - super(null, null, Adapter.INSTANCE); - } - - @Override - public void generate(ByteBufferPool.Lease lease) - { - } - - @Override - public void succeeded() - { - flusher.close(); - disconnect(); - } - - @Override - public void failed(Throwable x) - { - flusher.close(); - disconnect(); - } - - @Override - public String toString() - { - return String.format("%s@%x", "ShutdownFrame", hashCode()); - } - } - private class PromiseCallback<C> implements Callback { private final Promise<C> promise; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index 4557a1a9f61..e9edfee0d33 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -21,12 +21,13 @@ package org.eclipse.jetty.http2; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.util.Callback; public interface ISession extends Session { @Override - IStream getStream(int streamId); + public IStream getStream(int streamId); public void control(IStream stream, Frame frame, Callback callback); @@ -34,6 +35,8 @@ public interface ISession extends Session public int updateWindowSize(int delta); + public void onUpdateWindowSize(IStream stream, WindowUpdateFrame frame); + public void shutdown(); public void disconnect(); From 64e49a1fe5a39d07d1768990aabde29d7d4457d7 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 7 Aug 2014 09:10:35 +1000 Subject: [PATCH 208/269] work around classloaders for field preencoders --- .../jetty/http/PreEncodedHttpField.java | 19 +++++++++++++++++-- .../jetty/http2/hpack/HpackEncoder.java | 11 ++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index 9e47f50574e..f8f983a0b35 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -21,7 +21,9 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import org.eclipse.jetty.util.log.Log; @@ -45,8 +47,21 @@ public class PreEncodedHttpField extends HttpField static { List<HttpFieldPreEncoder> encoders = new ArrayList<>(); - for (HttpFieldPreEncoder enc : ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader())) - encoders.add(enc); + Iterator<HttpFieldPreEncoder> iter = ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader()).iterator(); + while (iter.hasNext()) + { + try + { + HttpFieldPreEncoder enc = iter.next(); + } + catch(Error|RuntimeException e) + { + LOG.debug(e); + } + } + // TODO avoid needing this catch all + if (encoders.size()==0) + encoders.add(new Http1FieldPreEncoder()); LOG.debug("HttpField encoders loaded: {}",encoders); __encoders = encoders.toArray(new HttpFieldPreEncoder[encoders.size()]); } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index 33c524984e5..fed4aa5b82e 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -53,8 +53,9 @@ public class HpackEncoder private final static EnumSet<HttpHeader> __DO_NOT_INDEX = EnumSet.of( - // TODO ??? HttpHeader.C_PATH, - // TODO ??? HttpHeader.DATE, + // HttpHeader.C_PATH, // TODO more data needed + // HttpHeader.DATE, // TODO more data needed + HttpHeader.AUTHORIZATION, HttpHeader.CONTENT_MD5, HttpHeader.CONTENT_RANGE, HttpHeader.ETAG, @@ -63,7 +64,9 @@ public class HpackEncoder HttpHeader.IF_NONE_MATCH, HttpHeader.IF_RANGE, HttpHeader.IF_MATCH, + HttpHeader.LOCATION, HttpHeader.RANGE, + HttpHeader.RETRY_AFTER, HttpHeader.EXPIRES, HttpHeader.LAST_MODIFIED, HttpHeader.SET_COOKIE, @@ -71,7 +74,9 @@ public class HpackEncoder private final static EnumSet<HttpHeader> __NEVER_INDEX = - EnumSet.of(HttpHeader.SET_COOKIE, + EnumSet.of( + HttpHeader.AUTHORIZATION, + HttpHeader.SET_COOKIE, HttpHeader.SET_COOKIE2); static From a4d4b3ab571fa56b02d611f2b565d03ccccb1347 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 7 Aug 2014 09:22:22 +1000 Subject: [PATCH 209/269] fix work around classloaders for field preencoders --- .../org/eclipse/jetty/http/PreEncodedHttpField.java | 2 +- .../org/eclipse/jetty/server/AbstractConnector.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index f8f983a0b35..6ae9e1fcb68 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -52,7 +52,7 @@ public class PreEncodedHttpField extends HttpField { try { - HttpFieldPreEncoder enc = iter.next(); + encoders.add(iter.next()); } catch(Error|RuntimeException e) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 3106eec2575..027f5a26075 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -366,6 +366,19 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co _defaultProtocol=factory.getProtocol(); } } + + public void addIfAbsentConnectionFactory(ConnectionFactory factory) + { + synchronized (_factories) + { + if (_factories.containsKey(factory.getProtocol())) + return; + _factories.put(factory.getProtocol().toLowerCase(Locale.ENGLISH), factory); + addBean(factory); + if (_defaultProtocol==null) + _defaultProtocol=factory.getProtocol(); + } + } public ConnectionFactory removeConnectionFactory(String protocol) { From 287e86b7aa787c9836fccbe2816dd08b4b6c599e Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 7 Aug 2014 12:58:12 +1000 Subject: [PATCH 210/269] decomposed https,http2 and spdy modules to share ServerConnector --- .../src/main/config/etc/protonego-alpn.xml | 32 ++- .../config/modules/protonego-impl/alpn.mod | 3 - .../server/ALPNServerConnectionFactory.java | 5 + .../main/resources/modules/ssl-protonego.mod | 11 + .../src/main/config/etc/jetty-http2.xml | 66 +----- .../src/main/config/modules/http2.mod | 8 +- .../src/main/config/etc/protonego-npn.xml | 32 ++- .../config/modules/protonego-impl/npn.mod | 3 - .../server/NPNServerConnectionFactory.java | 5 + .../src/main/config/etc/jetty-https.xml | 50 ++--- .../src/main/config/etc/jetty-ssl.xml | 59 ++++-- .../src/main/config/modules/https.mod | 6 - jetty-server/src/main/config/modules/ssl.mod | 7 + .../jetty/server/AbstractConnector.java | 34 ++- .../NegotiatingServerConnectionFactory.java | 12 +- .../jetty/server/SslConnectionFactory.java | 5 +- .../src/main/config/etc/jetty-spdy.xml | 200 ++++++------------ .../src/main/config/modules/spdy.mod | 9 +- .../java/org/eclipse/jetty/start/Modules.java | 5 +- .../org/eclipse/jetty/start/StartArgs.java | 1 + 20 files changed, 249 insertions(+), 304 deletions(-) create mode 100644 jetty-distribution/src/main/resources/modules/ssl-protonego.mod diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml index 3c1ed6daacc..657f8836e37 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml +++ b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml @@ -1,19 +1,29 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> -<Configure id="protonego" class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory"> - <Arg name="protocols"> - <Array type="String"> - <Item>spdy/3</Item> - <Item>spdy/2</Item> - <Item>http/1.1</Item> - </Array> +<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> + + <Call name="addConnectionFactory"> + <Arg> + <New class="org.eclipse.jetty.server.SslConnectionFactory"> + <Arg name="next"><Property name="protonego"/></Arg> + <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg> + </New> </Arg> + </Call> + + <Call name="addConnectionFactory"> + <Arg> + <New id="protonego" class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory"> + <Arg name="protocols"> + <Array type="String"></Array> + </Arg> + </New> + </Arg> + </Call> - <Set name="defaultProtocol">http/1.1</Set> - - <!-- Enables ALPN debugging on System.err --> - <!--<Set class="org.eclipse.jetty.alpn.ALPN" name="debug" type="boolean">true</Set>--> + <!-- Enables ALPN debugging on System.err --> + <!--<Set class="org.eclipse.jetty.alpn.ALPN" name="debug" type="boolean">true</Set>--> </Configure> diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod index 0e399f05cb1..ca51179c269 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod @@ -27,9 +27,6 @@ protonego-impl/alpn-${java.version} lib/jetty-alpn-client-${jetty.version}.jar lib/jetty-alpn-server-${jetty.version}.jar -[xml] -etc/protonego-alpn.xml - [files] lib/ lib/alpn/ diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index a6e386b7bda..3a0e50853a5 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -34,6 +34,11 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact { private static final Logger LOG = Log.getLogger(ALPNServerConnectionFactory.class); + public ALPNServerConnectionFactory() + { + this(new String[]{}); + } + public ALPNServerConnectionFactory(@Name("protocols") String... protocols) { super("alpn", protocols); diff --git a/jetty-distribution/src/main/resources/modules/ssl-protonego.mod b/jetty-distribution/src/main/resources/modules/ssl-protonego.mod new file mode 100644 index 00000000000..4a348a68297 --- /dev/null +++ b/jetty-distribution/src/main/resources/modules/ssl-protonego.mod @@ -0,0 +1,11 @@ +# +# SSL Protonegotiate module +# + +[depend] +ssl +protonego + +[xml] +etc/protonego-${protonego}.xml + diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml index 038f3d1371a..b0ad6581e10 100644 --- a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml +++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml @@ -2,60 +2,16 @@ <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <!-- ============================================================= --> -<!-- Configure a HTTP2 connector. --> +<!-- Configure a HTTP2 on the ssl connector. --> <!-- ============================================================= --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <Call id="http2Connector" name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"> - <Ref refid="Server"/> - </Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - - <!-- SSL Connection factory with 'protonego' as next protocol --> - <Item> - <New class="org.eclipse.jetty.server.SslConnectionFactory"> - <Arg name="next"><Property name="protonego"/></Arg> - <Arg name="sslContextFactory"> - <Ref refid="sslContextFactory"/> - </Arg> - </New> - </Item> - - <!-- Next Protocol Connection factory with HTTP/1.1 as default protocol --> - <Item> - <Ref refid="protonego"/> - </Item> - - <!-- HTTP/2 Connection factory --> - <Item> - <New class="org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory"> - <Arg name="config"> - <Ref refid="sslHttpConfig"/> - </Arg> - <Set name="maxConcurrentStreams"><Property name="http2.maxConcurrentStreams" default="1024"/></Set> - </New> - </Item> - - <!-- HTTP/1.1 Connection factory --> - <Item> - <New class="org.eclipse.jetty.server.HttpConnectionFactory"> - <Arg name="config"> - <Ref refid="sslHttpConfig"/> - </Arg> - </New> - </Item> - </Array> - </Arg> - - <Set name="host"><Property name="http2.host"/></Set> - <Set name="port"><Property name="http2.port" default="443"/></Set> - <Set name="idleTimeout"><Property name="http2.timeout" default="30000"/></Set> - </New> - </Arg> - </Call> - +<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> + <Call name="addConnectionFactory"> + <Arg> + <New class="org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory"> + <Arg name="config"><Ref refid="sslHttpConfig"/></Arg> + <Set name="maxConcurrentStreams"><Property name="http2.maxConcurrentStreams" default="1024"/></Set> + </New> + </Arg> + </Call> </Configure> + diff --git a/jetty-http2/http2-server/src/main/config/modules/http2.mod b/jetty-http2/http2-server/src/main/config/modules/http2.mod index b0d4bc8910a..f1a43941a97 100644 --- a/jetty-http2/http2-server/src/main/config/modules/http2.mod +++ b/jetty-http2/http2-server/src/main/config/modules/http2.mod @@ -3,8 +3,7 @@ # [depend] -ssl -protonego +ssl-protonego [lib] lib/http2/*.jar @@ -15,8 +14,3 @@ etc/jetty-http2.xml [ini-template] ## HTTP2 Configuration -# Port for HTTP2 connections -http2.port=8443 - -# HTTP2 idle timeout in milliseconds -http2.timeout=30000 diff --git a/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml b/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml index 743a5ecd6f1..2a24f6ca2d4 100644 --- a/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml +++ b/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml @@ -1,16 +1,28 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> -<Configure id="protonego" class="org.eclipse.jetty.npn.server.NPNServerConnectionFactory"> - <Arg name="protocols"> - <Array type="String"> - <Item>spdy/3</Item> - <Item>spdy/2</Item> - <Item>http/1.1</Item> - </Array> - </Arg> - - <Set name="defaultProtocol">http/1.1</Set> + +<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> + + <Call name="addConnectionFactory"> + <Arg> + <New class="org.eclipse.jetty.server.SslConnectionFactory"> + <Arg name="next"><Property name="protonego"/></Arg> + <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg> + </New> + </Arg> + </Call> + + <Call name="addConnectionFactory"> + <Arg> + <New id="protonego" class="org.eclipse.jetty.npn.server.NPNServerConnectionFactory"> + <Arg name="protocols"> + <Array type="String"> + </Array> + </Arg> + </New> + </Arg> + </Call> <!-- =========================================================== --> <!-- Enables NPN debugging on System.err --> diff --git a/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod index f9d02061fb1..a1bbc46ee46 100644 --- a/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod +++ b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod @@ -27,9 +27,6 @@ protonego-impl/npn-${java.version} lib/jetty-npn-client-${jetty.version}.jar lib/jetty-npn-server-${jetty.version}.jar -[xml] -etc/protonego-npn.xml - [files] lib/ lib/npn/ diff --git a/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java index 8c1cb190c54..39da0c404c9 100644 --- a/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java +++ b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java @@ -34,6 +34,11 @@ public class NPNServerConnectionFactory extends NegotiatingServerConnectionFacto { private static final Logger LOG = Log.getLogger(NPNServerConnectionFactory.class); + public NPNServerConnectionFactory() + { + this(new String[]{}); + } + public NPNServerConnectionFactory(@Name("protocols") String... protocols) { super("npn", protocols); diff --git a/jetty-server/src/main/config/etc/jetty-https.xml b/jetty-server/src/main/config/etc/jetty-https.xml index 419f8d19ee6..f27cec070bd 100644 --- a/jetty-server/src/main/config/etc/jetty-https.xml +++ b/jetty-server/src/main/config/etc/jetty-https.xml @@ -6,43 +6,23 @@ <!-- This configuration must be used in conjunction with jetty.xml --> <!-- and jetty-ssl.xml. --> <!-- ============================================================= --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> +<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> - <!-- =========================================================== --> - <!-- Add a HTTPS Connector. --> - <!-- Configure an o.e.j.server.ServerConnector with connection --> - <!-- factories for TLS (aka SSL) and HTTP to provide HTTPS. --> - <!-- All accepted TLS connections are wired to a HTTP connection.--> - <!-- --> - <!-- Consult the javadoc of o.e.j.server.ServerConnector, --> - <!-- o.e.j.server.SslConnectionFactory and --> - <!-- o.e.j.server.HttpConnectionFactory for all configuration --> - <!-- that may be set here. --> - <!-- =========================================================== --> - <Call id="httpsConnector" name="addConnector"> + <Call name="addIfAbsentConnectionFactory"> <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"><Ref refid="Server" /></Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - <Item> - <New class="org.eclipse.jetty.server.SslConnectionFactory"> - <Arg name="next">http/1.1</Arg> - <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg> - </New> - </Item> - <Item> - <New class="org.eclipse.jetty.server.HttpConnectionFactory"> - <Arg name="config"><Ref refid="sslHttpConfig"/></Arg> - </New> - </Item> - </Array> - </Arg> - <Set name="host"><Property name="jetty.host" /></Set> - <Set name="port"><Property name="https.port" default="443" /></Set> - <Set name="idleTimeout"><Property name="https.timeout" default="30000"/></Set> - <Set name="soLingerTime"><Property name="https.soLingerTime" default="-1"/></Set> - </New> + <New class="org.eclipse.jetty.server.SslConnectionFactory"> + <Arg name="next">http/1.1</Arg> + <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg> + </New> </Arg> </Call> + + <Call name="addConnectionFactory"> + <Arg> + <New class="org.eclipse.jetty.server.HttpConnectionFactory"> + <Arg name="config"><Ref refid="sslHttpConfig" /></Arg> + </New> + </Arg> + </Call> + </Configure> diff --git a/jetty-server/src/main/config/etc/jetty-ssl.xml b/jetty-server/src/main/config/etc/jetty-ssl.xml index 4ac2d3e240b..1014c8507a0 100644 --- a/jetty-server/src/main/config/etc/jetty-ssl.xml +++ b/jetty-server/src/main/config/etc/jetty-ssl.xml @@ -2,21 +2,45 @@ <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <!-- ============================================================= --> -<!-- Configure a TLS (SSL) Context Factory --> -<!-- This configuration must be used in conjunction with jetty.xml --> -<!-- and either jetty-https.xml or jetty-spdy.xml (but not both) --> +<!-- Base SSL configuration --> +<!-- This configuration needs to be used together with 1 or more --> +<!-- of jetty-https.xml, jetty-spdy.xml and/or jetty-http2.xml --> <!-- ============================================================= --> -<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> - <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.keystore" default="etc/keystore"/></Set> - <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> - <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set> - <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.truststore" default="etc/keystore"/></Set> - <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> - <Set name="EndpointIdentificationAlgorithm"></Set> - <Set name="NeedClientAuth"><Property name="jetty.ssl.needClientAuth" default="false"/></Set> - <Set name="WantClientAuth"><Property name="jetty.ssl.wantClientAuth" default="false"/></Set> - <Set name="ExcludeCipherSuites"> - <Array type="String"> +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <!-- =========================================================== --> + <!-- Add a SSL Connector with no protocol factories --> + <!-- =========================================================== --> + <Call name="addConnector"> + <Arg> + <New id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> + <Arg name="server"><Ref refid="Server" /></Arg> + <Arg name="factories"> + <Array type="org.eclipse.jetty.server.ConnectionFactory"> + </Array> + </Arg> + <Set name="host"><Property name="jetty.host" /></Set> + <Set name="port"><Property name="ssl.port" default="443" /></Set> + <Set name="idleTimeout"><Property name="ssl.timeout" default="30000"/></Set> + <Set name="soLingerTime"><Property name="ssl.soLingerTime" default="-1"/></Set> + </New> + </Arg> + </Call> + + <!-- ============================================================= --> + <!-- Create a TLS (SSL) Context Factory for later reuse --> + <!-- ============================================================= --> + <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> + <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.keystore" default="etc/keystore"/></Set> + <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> + <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set> + <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.truststore" default="etc/keystore"/></Set> + <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> + <Set name="EndpointIdentificationAlgorithm"></Set> + <Set name="NeedClientAuth"><Property name="jetty.ssl.needClientAuth" default="false"/></Set> + <Set name="WantClientAuth"><Property name="jetty.ssl.wantClientAuth" default="false"/></Set> + <Set name="ExcludeCipherSuites"> + <Array type="String"> <Item>SSL_RSA_WITH_DES_CBC_SHA</Item> <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item> <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item> @@ -24,9 +48,10 @@ <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item> <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item> <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item> - </Array> - </Set> - + </Array> + </Set> + </New> + <!-- =========================================================== --> <!-- Create a TLS specific HttpConfiguration based on the --> <!-- common HttpConfiguration defined in jetty.xml --> diff --git a/jetty-server/src/main/config/modules/https.mod b/jetty-server/src/main/config/modules/https.mod index bd1b718081c..d576c56258d 100644 --- a/jetty-server/src/main/config/modules/https.mod +++ b/jetty-server/src/main/config/modules/https.mod @@ -10,10 +10,4 @@ etc/jetty-https.xml [ini-template] ## HTTPS Configuration -# HTTP port to listen on -https.port=8443 -# HTTPS idle timeout in milliseconds -https.timeout=30000 -# HTTPS Socket.soLingerTime in seconds. (-1 to disable) -# https.soLingerTime=-1 diff --git a/jetty-server/src/main/config/modules/ssl.mod b/jetty-server/src/main/config/modules/ssl.mod index 449f58104fb..fa3229e245e 100644 --- a/jetty-server/src/main/config/modules/ssl.mod +++ b/jetty-server/src/main/config/modules/ssl.mod @@ -16,6 +16,13 @@ http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/ # define the port to use for secure redirection jetty.secure.port=8443 +# SSL port to listen on +ssl.port=8443 +# SSL idle timeout in milliseconds +ssl.timeout=30000 +# HTTPS Socket.soLingerTime in seconds. (-1 to disable) +# ssl.soLingerTime=-1 + # Setup a demonstration keystore and truststore jetty.keystore=etc/keystore jetty.truststore=etc/keystore diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 027f5a26075..89d22129cce 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -337,7 +337,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { synchronized (_factories) { - return _factories.get(protocol.toLowerCase(Locale.ENGLISH)); + return _factories.get(protocol); } } @@ -357,13 +357,20 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { synchronized (_factories) { - ConnectionFactory old=_factories.remove(factory.getProtocol()); + String key=factory.getProtocol(); + ConnectionFactory old=_factories.remove(key); if (old!=null) + { + if (old.getProtocol().equals(_defaultProtocol)) + _defaultProtocol=null; removeBean(old); - _factories.put(factory.getProtocol().toLowerCase(Locale.ENGLISH), factory); + LOG.info("{} removed {}",this,old); + } + _factories.put(key, factory); addBean(factory); if (_defaultProtocol==null) _defaultProtocol=factory.getProtocol(); + LOG.info("{} added {}",this,factory); } } @@ -371,12 +378,17 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { synchronized (_factories) { - if (_factories.containsKey(factory.getProtocol())) - return; - _factories.put(factory.getProtocol().toLowerCase(Locale.ENGLISH), factory); - addBean(factory); - if (_defaultProtocol==null) - _defaultProtocol=factory.getProtocol(); + String key=factory.getProtocol(); + if (_factories.containsKey(key)) + LOG.info("{} addIfAbsent ignored {}",this,factory); + else + { + _factories.put(key, factory); + addBean(factory); + if (_defaultProtocol==null) + _defaultProtocol=factory.getProtocol(); + LOG.info("{} addIfAbsent added {}",this,factory); + } } } @@ -384,7 +396,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { synchronized (_factories) { - ConnectionFactory factory= _factories.remove(protocol.toLowerCase(Locale.ENGLISH)); + ConnectionFactory factory= _factories.remove(protocol); removeBean(factory); return factory; } @@ -439,7 +451,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co public void setDefaultProtocol(String defaultProtocol) { - _defaultProtocol = defaultProtocol.toLowerCase(Locale.ENGLISH); + _defaultProtocol = defaultProtocol; if (isRunning()) _defaultConnectionFactory=getConnectionFactory(_defaultProtocol); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java index 08c8817189e..2daafb80f48 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java @@ -18,9 +18,11 @@ package org.eclipse.jetty.server; +import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; + import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.AbstractConnection; @@ -58,7 +60,7 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect public NegotiatingServerConnectionFactory(String protocol, String... protocols) { super(protocol); - this.protocols = Arrays.asList(protocols); + this.protocols = new ArrayList<String>(Arrays.asList(protocols)); } public String getDefaultProtocol() @@ -75,6 +77,11 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect { return protocols; } + + public void adProtocol(String protocol) + { + protocols.add(protocol); + } @Override public Connection newConnection(Connector connector, EndPoint endPoint) @@ -87,8 +94,7 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect while (i.hasNext()) { String protocol = i.next(); - String prefix = "ssl-"; - if (protocol.regionMatches(true, 0, prefix, 0, prefix.length()) || protocol.equalsIgnoreCase("alpn")) + if ("SSL".equalsIgnoreCase(protocol) || "alpn".equalsIgnoreCase("protocol")) { i.remove(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java index 5fcc1038da6..29c06b27171 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java @@ -47,7 +47,7 @@ public class SslConnectionFactory extends AbstractConnectionFactory public SslConnectionFactory(@Name("sslContextFactory") SslContextFactory factory, @Name("next") String nextProtocol) { - super("SSL-"+nextProtocol); + super("SSL"); _sslContextFactory=factory==null?new SslContextFactory():factory; _nextProtocol=nextProtocol; addBean(_sslContextFactory); @@ -97,6 +97,7 @@ public class SslConnectionFactory extends AbstractConnectionFactory @Override public String toString() { - return String.format("%s@%x{%s}",this.getClass().getSimpleName(),hashCode(),getProtocol()); + return String.format("%s@%x{%s->%s}",this.getClass().getSimpleName(),hashCode(),getProtocol(),_nextProtocol); } + } diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml index b094d7ce85b..fbaca7d5ef7 100644 --- a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml +++ b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml @@ -2,138 +2,76 @@ <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <!-- ============================================================= --> -<!-- Configure a SPDY connector. --> -<!-- This configuration must be used in conjunction with jetty.xml --> -<!-- and jetty-ssl.xml --> +<!-- Configure a SPDY on the ssl connector. --> <!-- ============================================================= --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> +<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> + + <!-- =========================================================== --> + <!-- Create a push strategy which can be used by reference by --> + <!-- individual connection factories below. --> + <!-- --> + <!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy --> + <!-- for all configuration that may be set here. --> + <!-- =========================================================== --> + <New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy"> + <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the + user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" --> + <!-- + <Set name="UserAgentBlacklist"> + <Array type="String"> + <Item>.*(?i)firefox/14.*</Item> + <Item>.*(?i)firefox/15.*</Item> + <Item>.*(?i)firefox/16.*</Item> + </Array> + </Set> + --> - <!-- =========================================================== --> - <!-- Create a push strategy which can be used by reference by --> - <!-- individual connection factories below. --> - <!-- --> - <!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy --> - <!-- for all configuration that may be set here. --> - <!-- =========================================================== --> - <New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy"> - <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the - user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" --> - <!-- - <Set name="UserAgentBlacklist"> - <Array type="String"> - <Item>.*(?i)firefox/14.*</Item> - <Item>.*(?i)firefox/15.*</Item> - <Item>.*(?i)firefox/16.*</Item> - </Array> - </Set> - --> - - <!-- Uncomment to override default file extensions to push --> - <!-- - <Set name="PushRegexps"> - <Array type="String"> - <Item>.*\.css</Item> - <Item>.*\.js</Item> - <Item>.*\.png</Item> - <Item>.*\.jpg</Item> - <Item>.*\.gif</Item> - </Array> - </Set> - --> - <Set name="referrerPushPeriod">5000</Set> - <Set name="maxAssociatedResources">32</Set> - </New> - - <!-- =========================================================== --> - <!-- Add a SPDY/HTTPS Connector. --> - <!-- Configure an o.e.j.server.ServerConnector with connection --> - <!-- factories for TLS (aka SSL), ProtoNego, SPDY and HTTP to --> - <!-- provide a connector that can accept HTTPS or SPDY --> - <!-- connections. --> - <!-- --> - <!-- All accepted TLS connections are initially wired to a --> - <!-- Protonego connection, which attempts to use a TLS extension --> - <!-- to negotiation the protocol. If it is not supported by --> - <!-- the client, then the connection is replaced by a HTTP --> - <!-- connection. If a specific protocol version (eg spdy/3) is --> - <!-- negotiated, then the appropriate connection factory --> - <!-- is used to create a connection to replace the connection --> - <!-- --> - <!-- The final result is a SPDY or HTTP connection wired behind --> - <!-- a TLS (aka SSL) connection. --> - <!-- --> - <!-- Consult the javadoc of o.e.j.server.ServerConnector and the --> - <!-- specific connection factory types for all configuration --> - <!-- that may be set here. --> - <!-- =========================================================== --> - <Call id="spdyConnector" name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"> - <Ref refid="Server"/> - </Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - - <!-- SSL Connection factory with Protonego as next protocol --> - <Item> - <New class="org.eclipse.jetty.server.SslConnectionFactory"> - <Arg name="next"><Property name="protonego"/></Arg> - <Arg name="sslContextFactory"> - <Ref refid="sslContextFactory"/> - </Arg> - </New> - </Item> - - <!-- NPN Connection factory with HTTP as default protocol --> - <Item> - <Ref refid="protonego"/> - </Item> - - <!-- SPDY/3 Connection factory --> - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">3</Arg> - <Arg name="config"> - <Ref refid="sslHttpConfig"/> - </Arg> - <!-- Set the initial window size for this SPDY connector. --> - <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> - <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set> - <!-- Uncomment to enable ReferrerPushStrategy --> - <!--<Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg>--> - </New> - </Item> - - <!-- SPDY/2 Connection factory --> - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">2</Arg> - <Arg name="config"> - <Ref refid="sslHttpConfig"/> - </Arg> - <!-- Set the initial window size for this SPDY connector. --> - <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> - <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set> - </New> - </Item> - - <!-- HTTP Connection factory --> - <Item> - <New class="org.eclipse.jetty.server.HttpConnectionFactory"> - <Arg name="config"> - <Ref refid="sslHttpConfig"/> - </Arg> - </New> - </Item> - </Array> - </Arg> - - <Set name="host"><Property name="jetty.host"/></Set> - <Set name="port"><Property name="spdy.port" default="443"/></Set> - <Set name="idleTimeout"><Property name="spdy.timeout" default="30000"/></Set> - </New> - </Arg> - </Call> + <!-- Uncomment to override default file extensions to push --> + <!-- + <Set name="PushRegexps"> + <Array type="String"> + <Item>.*\.css</Item> + <Item>.*\.js</Item> + <Item>.*\.png</Item> + <Item>.*\.jpg</Item> + <Item>.*\.gif</Item> + </Array> + </Set> + --> + <Set name="referrerPushPeriod">5000</Set> + <Set name="maxAssociatedResources">32</Set> + </New> + <!-- =========================================================== --> + <!-- Add a SPDY/HTTPS Connector factory --> + <!-- =========================================================== --> + + <!-- SPDY/3 Connection factory --> + <Call name="addConnectionFactory"> + <Arg> + <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> + <Arg name="version" type="int">3</Arg> + <Arg name="config"><Ref refid="sslHttpConfig"/></Arg> + <!-- Set the initial window size for this SPDY connector. --> + <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> + <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set> + <!-- Uncomment to enable ReferrerPushStrategy --> + <!--<Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg>--> + </New> + </Arg> + </Call> + + <!-- SPDY/2 Connection factory --> + <Call name="addConnectionFactory"> + <Arg> + <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> + <Arg name="version" type="int">2</Arg> + <Arg name="config"><Ref refid="sslHttpConfig"/></Arg> + <!-- Set the initial window size for this SPDY connector. --> + <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> + <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set> + </New> + </Arg> + </Call> + </Configure> diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod index cf79dfa0f20..cb4cf971c7d 100644 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod +++ b/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod @@ -3,8 +3,7 @@ # [depend] -ssl -protonego +ssl-protonego [lib] lib/spdy/*.jar @@ -16,11 +15,5 @@ etc/jetty-spdy.xml [ini-template] ## SPDY Configuration -# Port for SPDY connections -spdy.port=8443 - -# SPDY idle timeout in milliseconds -spdy.timeout=30000 - # Initial Window Size for SPDY #spdy.initialWindowSize=65536 diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java index 804d63ae325..c0570a36041 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java @@ -313,9 +313,10 @@ public class Modules implements Iterable<Module> if (module.isEnabled()) { // already enabled, skip + module.addSources(sources); return; } - + StartLog.debug("Enabling module: %s (via %s)",module.getName(),Main.join(sources,", ")); module.setEnabled(true); args.parseModule(module); @@ -348,7 +349,7 @@ public class Modules implements Iterable<Module> } if (parent != null) { - enableModule(parent,sources); + enableModule(parent,new ArrayList<String>()); } } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java index 4aff293052b..06b92461dd7 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java @@ -425,6 +425,7 @@ public class StartArgs for (String xmlRef : module.getXmls()) { // Straight Reference + xmlRef=properties.expand(xmlRef); Path xmlfile = baseHome.getPath(xmlRef); addUniqueXmlFile(xmlRef,xmlfile); } From 6dfa452e29ca3ea5ee63552f9cefb0dd07899fa3 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 7 Aug 2014 19:00:31 +1000 Subject: [PATCH 211/269] case insensitive protocols --- .../java/org/eclipse/jetty/embedded/LikeJettyXml.java | 3 ++- .../org/eclipse/jetty/embedded/ManyConnectors.java | 3 ++- .../org/eclipse/jetty/server/AbstractConnector.java | 11 ++++++----- .../eclipse/jetty/server/HttpConnectionFactory.java | 2 +- .../jetty/spdy/server/ALPNNegotiationTest.java | 2 +- .../jetty/websocket/server/SimpleServletServer.java | 3 ++- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java index b53f55cfc81..e6bde9223c3 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java @@ -23,6 +23,7 @@ import java.lang.management.ManagementFactory; import org.eclipse.jetty.deploy.DeploymentManager; import org.eclipse.jetty.deploy.PropertiesConfigurationManager; import org.eclipse.jetty.deploy.providers.WebAppProvider; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.security.HashLoginService; import org.eclipse.jetty.server.Handler; @@ -122,7 +123,7 @@ public class LikeJettyXml // SSL Connector ServerConnector sslConnector = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory,"http/1.1"), + new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(https_config)); sslConnector.setPort(8443); server.addConnector(sslConnector); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java index 78e595909b5..4bca8dfa9f5 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.embedded; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; @@ -83,7 +84,7 @@ public class ManyConnectors // We create a second ServerConnector, passing in the http configuration we just made along with the // previously created ssl context factory. Next we set the port and a longer idle timeout. ServerConnector https = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory,"http/1.1"), + new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(https_config)); https.setPort(8443); https.setIdleTimeout(500000); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 89d22129cce..893de2f9d62 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -37,6 +37,7 @@ import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.FutureCallback; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.ContainerLifeCycle; @@ -337,7 +338,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { synchronized (_factories) { - return _factories.get(protocol); + return _factories.get(StringUtil.asciiToLowerCase(protocol)); } } @@ -357,7 +358,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { synchronized (_factories) { - String key=factory.getProtocol(); + String key=StringUtil.asciiToLowerCase(factory.getProtocol()); ConnectionFactory old=_factories.remove(key); if (old!=null) { @@ -378,7 +379,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { synchronized (_factories) { - String key=factory.getProtocol(); + String key=StringUtil.asciiToLowerCase(factory.getProtocol()); if (_factories.containsKey(key)) LOG.info("{} addIfAbsent ignored {}",this,factory); else @@ -396,7 +397,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { synchronized (_factories) { - ConnectionFactory factory= _factories.remove(protocol); + ConnectionFactory factory= _factories.remove(StringUtil.asciiToLowerCase(protocol)); removeBean(factory); return factory; } @@ -451,7 +452,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co public void setDefaultProtocol(String defaultProtocol) { - _defaultProtocol = defaultProtocol; + _defaultProtocol = StringUtil.asciiToLowerCase(defaultProtocol); if (isRunning()) _defaultConnectionFactory=getConnectionFactory(_defaultProtocol); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java index ce6ffdb7b4b..d8790748126 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java @@ -44,7 +44,7 @@ public class HttpConnectionFactory extends AbstractConnectionFactory implements public HttpConnectionFactory(@Name("config") HttpConfiguration config) { - super(HttpVersion.HTTP_1_1.toString()); + super(HttpVersion.HTTP_1_1.asString()); _config=config; addBean(_config); } diff --git a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java b/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java index 0f3c4be759b..d471f768b5d 100644 --- a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java +++ b/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java @@ -133,7 +133,7 @@ public class ALPNNegotiationTest extends AbstractALPNTest @Override public void selected(String protocol) { - Assert.assertEquals("http/1.1", protocol); + Assert.assertEquals("http/1.1", protocol.toLowerCase()); } }); diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java index 4ec28fb229a..1b05cdd6b2f 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java @@ -22,6 +22,7 @@ import java.net.URI; import javax.servlet.http.HttpServlet; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.SecureRequestCustomizer; @@ -100,7 +101,7 @@ public class SimpleServletServer https_config.addCustomizer(new SecureRequestCustomizer()); // SSL Connector - connector = new ServerConnector(server,new SslConnectionFactory(sslContextFactory,"http/1.1"),new HttpConnectionFactory(https_config)); + connector = new ServerConnector(server,new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),new HttpConnectionFactory(https_config)); connector.setPort(0); } else From 69927b935eb0659945a72af2b9cc1a9e50f92e92 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 8 Aug 2014 01:09:18 +0200 Subject: [PATCH 212/269] Don't send a window update if the length is zero. --- .../java/org/eclipse/jetty/http2/HTTP2FlowControl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index efa5e5545a8..8f69833c527 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -99,9 +99,13 @@ public class HTTP2FlowControl implements FlowControl if (LOG.isDebugEnabled()) LOG.debug("Data consumed, increasing window by {} for {}", length, stream); - // Negative streamId allow for generation of bytes for both stream and session - WindowUpdateFrame frame = new WindowUpdateFrame(-stream.getId(), length); - stream.getSession().control(stream, frame, Callback.Adapter.INSTANCE); + + if (length > 0) + { + // Negative streamId allow for generation of bytes for both stream and session + WindowUpdateFrame frame = new WindowUpdateFrame(-stream.getId(), length); + stream.getSession().control(stream, frame, Callback.Adapter.INSTANCE); + } } @Override From 466d8db8d84fb82d4630c9cce5d956cc904176da Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 8 Aug 2014 01:10:51 +0200 Subject: [PATCH 213/269] Sending a SETTINGS frame after the preface, as required by the spec. --- .../client/HTTP2ClientConnectionFactory.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index a3c6ac10a45..27053b77061 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -20,14 +20,17 @@ package org.eclipse.jetty.http2.client; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.PrefaceParser; @@ -67,6 +70,7 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory private class HTTP2ClientConnection extends HTTP2Connection implements Callback { + private final AtomicBoolean prefaceSent = new AtomicBoolean(); private final HTTP2Client client; private final Promise<Session> promise; @@ -94,8 +98,18 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory @Override public void succeeded() { - client.addSession(getSession()); - promise.succeeded(getSession()); + if (prefaceSent.compareAndSet(false, true)) + { + // SPEC: after the preface bytes, a SETTINGS frame must be sent. + // TODO: configure settings. + HashMap<Integer, Integer> settings = new HashMap<>(); + getSession().settings(new SettingsFrame(settings, false), this); + } + else + { + client.addSession(getSession()); + promise.succeeded(getSession()); + } } @Override From 6b9a069d9d337f452891b13db28bfb313e35a3b6 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 8 Aug 2014 01:11:11 +0200 Subject: [PATCH 214/269] Waiting for all the frames to arrive before stopping. --- .../java/org/eclipse/jetty/http2/client/Client.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java index 0fd6ed9f6a2..eea82ed21d7 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java @@ -29,7 +29,9 @@ import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.Promise; @@ -60,7 +62,16 @@ public class Client public void onHeaders(Stream stream, HeadersFrame frame) { System.err.println(frame.getMetaData()); - latch.countDown(); + if (frame.isEndStream()) + latch.countDown(); + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + latch.countDown(); } }); From 4d7ead76ce0e24c0a1f180a8fd218bc251068a29 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 8 Aug 2014 17:00:47 +1000 Subject: [PATCH 215/269] basic push cache filter --- .../src/main/java/org/eclipse/jetty/http/HttpFields.java | 2 +- .../main/java/org/eclipse/jetty/server/Dispatcher.java | 6 ++++++ .../test-jetty-webapp/src/main/webapp/WEB-INF/web.xml | 9 +++++++++ .../src/test/java/org/eclipse/jetty/TestServer.java | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 54b2f98202f..66d69c29d0e 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -76,7 +76,7 @@ public class HttpFields implements Iterable<HttpField> */ public HttpFields(HttpFields fields) { - _fields=Arrays.copyOf(fields._fields,_fields.length+10); + _fields=Arrays.copyOf(fields._fields,fields._fields.length+10); _size=fields._size; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java index e1b563b381d..c105b3cfd78 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java @@ -236,6 +236,12 @@ public class Dispatcher implements RequestDispatcher baseRequest.getHttpChannel().getHttpTransport().push(push); } + + @Override + public String toString() + { + return String.format("Dispatcher@0x%x{%s,%s}",hashCode(),_named,_uri); + } private void commitResponse(ServletResponse response, Request baseRequest) throws IOException { diff --git a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml index a2b37637578..81a3a4cd77a 100644 --- a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml +++ b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml @@ -18,6 +18,15 @@ <listener-class>com.acme.TestListener</listener-class> </listener> + <filter> + <filter-name>PushFilter</filter-name> + <filter-class>org.eclipse.jetty.servlets.PushCacheFilter</filter-class> + <async-supported>true</async-supported> + </filter> + <filter-mapping> + <filter-name>PushFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> <filter> <filter-name>QoSFilter</filter-name> diff --git a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java index 485ffeb4878..e10e6d0a529 100644 --- a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java +++ b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java @@ -158,6 +158,7 @@ public class TestServer server.setStopAtShutdown(true); WebAppContext webapp = new WebAppContext(); + webapp.setContextPath("/test"); webapp.setParentLoaderPriority(true); webapp.setResourceBase("./src/main/webapp"); webapp.setAttribute("testAttribute","testValue"); From c7d0bfce206a14add451eff427130500148c69d7 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 8 Aug 2014 18:01:09 +1000 Subject: [PATCH 216/269] basic push cache filter --- .../jetty/servlets/PushCacheFilter.java | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java new file mode 100644 index 00000000000..09af845edc0 --- /dev/null +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java @@ -0,0 +1,187 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.servlets; + +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.server.Dispatcher; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.util.URIUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + + +/* ------------------------------------------------------------ */ +/** + * A filter that builds a cache of associated resources to push + * using the following heuristics:<ul> + * <li>If a request has a If-xxx header, this suggests it's cache is already hot, + * so no resources are pushed. + * <li>If a request has a referrer header that matches this site, then + * this indicates that it is an associated resource + * <li>If the time period between a request and an associated request is small, + * that indicates a possible push resource + * </ul> + * + */ +public class PushCacheFilter implements Filter +{ + private static final Logger LOG = Log.getLogger(PushCacheFilter.class); + private final ConcurrentMap<String, Target> _cache = new ConcurrentHashMap<>(); + + private long _associateDelay=2000L; + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) + */ + @Override + public void init(FilterConfig config) throws ServletException + { + if (config.getInitParameter("associateDelay")!=null) + _associateDelay=Long.valueOf(config.getInitParameter("associateDelay")); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException + { + Request baseRequest = Request.getBaseRequest(request); + + + // Iterating over fields is more efficient than multiple gets + HttpFields fields = baseRequest.getHttpFields(); + boolean conditional=false; + String referer=null; + loop: for (int i=0;i<fields.size();i++) + { + HttpField field=fields.getField(i); + HttpHeader header=field.getHeader(); + if (header==null) + continue; + + switch (header) + { + case IF_MATCH: + case IF_MODIFIED_SINCE: + case IF_NONE_MATCH: + case IF_UNMODIFIED_SINCE: + conditional=true; + break loop; + + case REFERER: + referer=field.getValue(); + break; + + default: + break; + } + } + + if (LOG.isDebugEnabled()) + LOG.debug("{} {} referer={} conditional={}%n",baseRequest.getMethod(),baseRequest.getRequestURI(),referer,conditional); + + HttpURI uri = null; + if (!conditional) + { + String session = baseRequest.getSession(true).getId(); + String path = URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo()); + + if (referer!=null) + { + uri = new HttpURI(referer); + if (request.getServerName().equals(uri.getHost())) + { + String from = uri.getPath(); + if (from.startsWith(baseRequest.getContextPath())) + { + String from_in_ctx = from.substring(baseRequest.getContextPath().length()); + + Target target = _cache.get(from_in_ctx); + if (target!=null) + { + Long last = target._timestamp.get(session); + if (last!=null && (System.currentTimeMillis()-last)<_associateDelay && !target._associated.containsKey(path)) + { + RequestDispatcher dispatcher = baseRequest.getServletContext().getRequestDispatcher(path); + if (target._associated.putIfAbsent(path,dispatcher)==null) + LOG.info("ASSOCIATE {}->{}",from_in_ctx,dispatcher); + } + } + } + } + } + + // push some resources? + Target target = _cache.get(path); + if (target == null) + { + Target t=new Target(); + target = _cache.putIfAbsent(path,t); + target = target==null?t:target; + } + target._timestamp.put(session,System.currentTimeMillis()); + if (target._associated.size()>0) + { + for (RequestDispatcher dispatcher : target._associated.values()) + { + LOG.info("PUSH {}->{}",path,dispatcher); + ((Dispatcher)dispatcher).push(request); + } + } + } + + chain.doFilter(request,response); + + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#destroy() + */ + @Override + public void destroy() + { + } + + + public static class Target + { + final ConcurrentMap<String,RequestDispatcher> _associated = new ConcurrentHashMap<>(); + final ConcurrentMap<String,Long> _timestamp = new ConcurrentHashMap<>(); + } +} From 5da39140df1586955dcfad8d2ee65062e2c068e3 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 8 Aug 2014 18:30:56 +1000 Subject: [PATCH 217/269] remove old TODOs --- .../org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java | 1 - .../src/main/java/org/eclipse/jetty/server/HttpChannel.java | 1 - 2 files changed, 2 deletions(-) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 6b4b114aadf..2bd2ef98cb7 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -77,7 +77,6 @@ public class HttpChannelOverHTTP2 extends HttpChannel _expect100Continue = fields.contains(HttpHeader.EXPECT,HttpHeaderValue.CONTINUE.asString()); - // TODO make this a better field for h2 hpack generation HttpFields response=getResponse().getHttpFields(); if (getHttpConfiguration().getSendServerVersion()) response.add(SERVER_VERSION); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index dc8b0ebc889..8932bd9742e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -458,7 +458,6 @@ public class HttpChannel implements Runnable _request.setTimeStamp(System.currentTimeMillis()); _request.setMetaData(request); - // TODO make this a better field for h2 hpack generation if (_configuration.getSendDateHeader()) _response.getHttpFields().put(_connector.getServer().getDateField()); } From 3ace246cffb77c7237d41aca74888872bc97d882 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 8 Aug 2014 18:16:56 +0200 Subject: [PATCH 218/269] Catching Throwable instead of Exception. --- .../src/main/java/org/eclipse/jetty/client/HttpContent.java | 2 +- .../src/main/java/org/eclipse/jetty/client/HttpRequest.java | 2 +- .../src/main/java/org/eclipse/jetty/client/HttpSender.java | 3 +-- .../src/main/java/org/eclipse/jetty/client/api/Response.java | 2 +- .../org/eclipse/jetty/client/http/HttpSenderOverHTTP.java | 2 +- .../org/eclipse/jetty/client/util/PathContentProvider.java | 4 ++-- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java index 598d11e133f..27868e8f075 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java @@ -174,7 +174,7 @@ public class HttpContent implements Callback, Closeable if (iterator instanceof Closeable) ((Closeable)iterator).close(); } - catch (Exception x) + catch (Throwable x) { LOG.ignore(x); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java index 6a5a9c66c94..595aa00e2f7 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java @@ -489,7 +489,7 @@ public class HttpRequest implements Request listener.onContent(response, content); callback.succeeded(); } - catch (Exception x) + catch (Throwable x) { callback.failed(x); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java index 85d4d0b55ad..be65839387c 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java @@ -643,8 +643,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener content.succeeded(); process(); } - // Catch-all for runtime exceptions - catch (Exception x) + catch (Throwable x) { anyToFailure(x); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java index 1f92b1eb74d..72c85bce73e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java @@ -238,7 +238,7 @@ public interface Response onContent(response, content); callback.succeeded(); } - catch (Exception x) + catch (Throwable x) { callback.failed(x); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java index c8ce04168ab..b4717531985 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java @@ -180,7 +180,7 @@ public class HttpSenderOverHTTP extends HttpSender } } } - catch (Exception x) + catch (Throwable x) { if (LOG.isDebugEnabled()) LOG.debug(x); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java index e69a2e6e6ac..ea7b3c1f8d3 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java @@ -131,7 +131,7 @@ public class PathContentProvider extends AbstractTypedContentProvider close(); throw x; } - catch (Exception x) + catch (Throwable x) { close(); throw (NoSuchElementException)new NoSuchElementException().initCause(x); @@ -152,7 +152,7 @@ public class PathContentProvider extends AbstractTypedContentProvider if (channel != null) channel.close(); } - catch (Exception x) + catch (Throwable x) { LOG.ignore(x); } From ab96bf775fbde85ac29f4a1f8c2a949044685f69 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 8 Aug 2014 18:19:02 +0200 Subject: [PATCH 219/269] Removed unneeded casting to DataFrame. --- .../org/eclipse/jetty/http2/generator/DataGenerator.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index 1a2c42d31f2..d6d0c547561 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -36,10 +36,9 @@ public class DataGenerator this.headerGenerator = headerGenerator; } - public void generate(ByteBufferPool.Lease lease, Frame frame, int maxLength) + public void generate(ByteBufferPool.Lease lease, DataFrame frame, int maxLength) { - DataFrame dataFrame = (DataFrame)frame; - generateData(lease, dataFrame.getStreamId(), dataFrame.getData(), dataFrame.isEndStream(), maxLength); + generateData(lease, frame.getStreamId(), frame.getData(), frame.isEndStream(), maxLength); } public void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, int maxLength) From f8086dc7c26cbbf7e5092a86ba55c9ebb2212d8f Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 8 Aug 2014 23:52:20 +0200 Subject: [PATCH 220/269] Refactored the send of the SETTINGS frame from the client. It's now sent after a call to onPreface(), which has been moved to the common interface Session.Listener (from ServerSession.Listener), so that client applications can customize the SETTINGS to send to the server. --- .../client/HTTP2ClientConnectionFactory.java | 34 ++++----- .../jetty/http2/client/FlowControlTest.java | 71 +++++++++++++++++++ .../org/eclipse/jetty/http2/api/Session.java | 9 +++ .../api/server/ServerSessionListener.java | 10 --- .../jetty/http2/frames/SettingsFrame.java | 12 ++++ .../http2/generator/SettingsGenerator.java | 8 ++- .../frames/SettingsGenerateParseTest.java | 6 +- 7 files changed, 113 insertions(+), 37 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index 27053b77061..e03a8438e44 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -19,21 +19,17 @@ package org.eclipse.jetty.http2.client; import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.HashMap; +import java.util.Collections; import java.util.Map; import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; -import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; -import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.Connection; @@ -63,29 +59,33 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory Promise<Session> promise = (Promise<Session>)context.get(SESSION_PROMISE_CONTEXT_KEY); Generator generator = new Generator(byteBufferPool, 4096); - HTTP2Session session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, new HTTP2FlowControl(65535)); + HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, new HTTP2FlowControl(65535)); Parser parser = new Parser(byteBufferPool, session, 4096, 8192); - return new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, 8192, promise); + return new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, 8192, promise, listener); } private class HTTP2ClientConnection extends HTTP2Connection implements Callback { - private final AtomicBoolean prefaceSent = new AtomicBoolean(); private final HTTP2Client client; private final Promise<Session> promise; + private final Session.Listener listener; - public HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise) + public HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise, Session.Listener listener) { super(byteBufferPool, executor, endpoint, parser, session, bufferSize); this.client = client; this.promise = promise; + this.listener = listener; } @Override public void onOpen() { super.onOpen(); - getEndPoint().write(this, ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES)); + Map<Integer, Integer> settings = listener.onPreface(getSession()); + if (settings == null) + settings = Collections.emptyMap(); + getSession().settings(new SettingsFrame(settings, false, true), this); } @Override @@ -98,18 +98,8 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory @Override public void succeeded() { - if (prefaceSent.compareAndSet(false, true)) - { - // SPEC: after the preface bytes, a SETTINGS frame must be sent. - // TODO: configure settings. - HashMap<Integer, Integer> settings = new HashMap<>(); - getSession().settings(new SettingsFrame(settings, false), this); - } - else - { - client.addSession(getSession()); - promise.succeeded(getSession()); - } + client.addSession(getSession()); + promise.succeeded(getSession()); } @Override diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index dabd221d952..4879e128eea 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -531,4 +531,75 @@ public class FlowControlTest extends AbstractTest Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); } + + @Test + public void testClientSendingInitialSmallWindow() throws Exception + { + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + return new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + // Since we echo back the data + // asynchronously we must copy it. + ByteBuffer data = frame.getData(); + ByteBuffer copy = ByteBuffer.allocateDirect(data.remaining()); + copy.put(data).flip(); + stream.data(new DataFrame(stream.getId(), copy, frame.isEndStream()), callback); + } + }; + } + }); + + final int initialWindow = 16; + Session session = newClient(new Session.Listener.Adapter() + { + @Override + public Map<Integer, Integer> onPreface(Session session) + { + Map<Integer, Integer> settings = new HashMap<>(); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, initialWindow); + return settings; + } + }); + + byte[] requestData = new byte[initialWindow * 4]; + new Random().nextBytes(requestData); + + byte[] responseData = new byte[requestData.length]; + final ByteBuffer responseContent = ByteBuffer.wrap(responseData); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, false); + FuturePromise<Stream> streamPromise = new FuturePromise<>(); + final CountDownLatch latch = new CountDownLatch(1); + session.newStream(requestFrame, streamPromise, new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + responseContent.put(frame.getData()); + callback.succeeded(); + if (frame.isEndStream()) + latch.countDown(); + } + }); + Stream stream = streamPromise.get(5, TimeUnit.SECONDS); + + ByteBuffer requestContent = ByteBuffer.wrap(requestData); + DataFrame dataFrame = new DataFrame(stream.getId(), requestContent, true); + stream.data(dataFrame, Callback.Adapter.INSTANCE); + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + + responseContent.flip(); + Assert.assertArrayEquals(requestData, responseData); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java index d6a2697b554..3249a4d60bf 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.http2.api; import java.util.Collection; +import java.util.Map; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -48,6 +49,8 @@ public interface Session public interface Listener { + public Map<Integer,Integer> onPreface(Session session); + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame); public void onSettings(Session session, SettingsFrame frame); @@ -62,6 +65,12 @@ public interface Session public static class Adapter implements Session.Listener { + @Override + public Map<Integer, Integer> onPreface(Session session) + { + return null; + } + @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java index dc1ce9152c6..3eb90e8867b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java @@ -18,27 +18,17 @@ package org.eclipse.jetty.http2.api.server; -import java.util.Map; - import org.eclipse.jetty.http2.api.Session; public interface ServerSessionListener extends Session.Listener { public void onConnect(Session session); - public Map<Integer,Integer> onPreface(Session session); - public static class Adapter extends Session.Listener.Adapter implements ServerSessionListener { @Override public void onConnect(Session session) { } - - @Override - public Map<Integer, Integer> onPreface(Session session) - { - return null; - } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java index ef7a53b572e..f5f2a0b37e0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -30,12 +30,19 @@ public class SettingsFrame extends Frame private final Map<Integer, Integer> settings; private final boolean reply; + private boolean preface; public SettingsFrame(Map<Integer, Integer> settings, boolean reply) + { + this(settings, reply, false); + } + + public SettingsFrame(Map<Integer, Integer> settings, boolean reply, boolean preface) { super(FrameType.SETTINGS); this.settings = settings; this.reply = reply; + this.preface = preface; } public Map<Integer, Integer> getSettings() @@ -47,4 +54,9 @@ public class SettingsFrame extends Frame { return reply; } + + public boolean isPreface() + { + return preface; + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index dde019225ff..8430ddf170e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -25,6 +25,7 @@ import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; @@ -39,11 +40,14 @@ public class SettingsGenerator extends FrameGenerator public void generate(ByteBufferPool.Lease lease, Frame frame) { SettingsFrame settingsFrame = (SettingsFrame)frame; - generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply()); + generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply(), settingsFrame.isPreface()); } - public void generateSettings(ByteBufferPool.Lease lease, Map<Integer, Integer> settings, boolean reply) + public void generateSettings(ByteBufferPool.Lease lease, Map<Integer, Integer> settings, boolean reply, boolean preface) { + if (preface) + lease.append(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); + // Two bytes for the identifier, four bytes for the value. int entryLength = 2 + 4; int length = entryLength * settings.size(); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index c23674819ef..9f976a0722a 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -87,7 +87,7 @@ public class SettingsGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings, true); + generator.generateSettings(lease, settings, true, false); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -120,7 +120,7 @@ public class SettingsGenerateParseTest Map<Integer, Integer> settings1 = new HashMap<>(); settings1.put(13, 17); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings1, true); + generator.generateSettings(lease, settings1, true, false); // Modify the length of the frame to make it invalid ByteBuffer bytes = lease.getByteBuffers().get(0); bytes.putShort(1, (short)(bytes.getShort(1) - 1)); @@ -158,7 +158,7 @@ public class SettingsGenerateParseTest settings1.put(key, value); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings1, true); + generator.generateSettings(lease, settings1, true, false); for (ByteBuffer buffer : lease.getByteBuffers()) { From 59a9c0890c5ef01e6952e7745b991cfc1d82160c Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 8 Aug 2014 23:53:18 +0200 Subject: [PATCH 221/269] Fixed off-by-one in counting the padding bytes. --- .../java/org/eclipse/jetty/http2/parser/DataBodyParser.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index 44347454e6b..54d08679528 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.util.BufferUtil; public class DataBodyParser extends BodyParser { private State state = State.PREPARE; + private int padding; private int paddingLength; private int length; @@ -38,6 +39,7 @@ public class DataBodyParser extends BodyParser private void reset() { state = State.PREPARE; + padding = 0; paddingLength = 0; length = 0; } @@ -81,6 +83,7 @@ public class DataBodyParser extends BodyParser } case PADDING_LENGTH: { + padding = 1; // We have seen this byte. paddingLength = buffer.get() & 0xFF; --length; length -= paddingLength; @@ -109,7 +112,7 @@ public class DataBodyParser extends BodyParser loop = paddingLength == 0; // Padding bytes include the bytes that define the // padding length plus the actual padding bytes. - if (onData(slice, false, 1 + paddingLength)) + if (onData(slice, false, padding + paddingLength)) { return Result.ASYNC; } From 187c42fa4a9f63dc6fefdad9fa8b0071a595a81b Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 11 Aug 2014 11:30:49 +0200 Subject: [PATCH 222/269] Closing the flusher instead of just disconnecting after a GO_AWAY. This ensures that frames that may have been added to the flusher queue concurrently after the GO_AWAY are properly failed and the queue drained. --- .../main/java/org/eclipse/jetty/http2/HTTP2Flusher.java | 7 ------- .../main/java/org/eclipse/jetty/http2/HTTP2Session.java | 7 ++----- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java index fdbb23a773e..78848c5279b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java @@ -300,13 +300,6 @@ public class HTTP2Flusher extends IteratingCallback terminate(x); } - @Override - public void close() - { - super.close(); - iterate(); - } - private void terminate(Throwable x) { Queue<Entry> queued; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 1f763d89b87..1852df83fb6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -355,10 +355,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void reset(ResetFrame frame, Callback callback) { - if (closed.get()) - callback.succeeded(); - else - control(getStream(frame.getStreamId()), frame, callback); + control(getStream(frame.getStreamId()), frame, callback); } @Override @@ -662,7 +659,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } case GO_AWAY: { - disconnect(); + flusher.close(); break; } default: From 107a4fff20276753a0275d863793c730964996e4 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 11 Aug 2014 18:43:50 +0200 Subject: [PATCH 223/269] Fixed handling of INITIAL_WINDOW_SIZE setting. It must update only stream windows, and not the session window. --- .../client/HTTP2ClientConnectionFactory.java | 3 +- .../jetty/http2/client/FlowControlTest.java | 81 +++++++++++-------- .../org/eclipse/jetty/http2/FlowControl.java | 2 + .../eclipse/jetty/http2/HTTP2FlowControl.java | 5 +- .../org/eclipse/jetty/http2/HTTP2Session.java | 2 +- .../AbstractHTTP2ServerConnectionFactory.java | 3 +- 6 files changed, 56 insertions(+), 40 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index e03a8438e44..fd2b41b108a 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.Map; import java.util.concurrent.Executor; +import org.eclipse.jetty.http2.FlowControl; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.ISession; @@ -59,7 +60,7 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory Promise<Session> promise = (Promise<Session>)context.get(SESSION_PROMISE_CONTEXT_KEY); Generator generator = new Generator(byteBufferPool, 4096); - HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, new HTTP2FlowControl(65535)); + HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, new HTTP2FlowControl(FlowControl.DEFAULT_WINDOW_SIZE)); Parser parser = new Parser(byteBufferPool, session, 4096, 8192); return new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, 8192, promise, listener); } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index 4879e128eea..f92b36021b0 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -32,6 +32,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.FlowControl; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; @@ -334,53 +335,54 @@ public class FlowControlTest extends AbstractTest public void testSessionStalledStallsNewStreams() throws Exception { final int windowSize = 1024; - final CountDownLatch settingsLatch = new CountDownLatch(1); startServer(new ServerSessionListener.Adapter() { - @Override - public void onSettings(Session session, SettingsFrame frame) - { - settingsLatch.countDown(); - } - @Override public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) { - // For every stream, send down half the window size of data. - MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); - HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); - stream.headers(responseFrame, Callback.Adapter.INSTANCE); - DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(windowSize / 2), true); - stream.data(dataFrame, Callback.Adapter.INSTANCE); - return null; + MetaData.Request request = (MetaData.Request)requestFrame.getMetaData(); + if ("POST".equalsIgnoreCase(request.getMethod())) + { + // Send data to consume the session window. + ByteBuffer data = ByteBuffer.allocate(FlowControl.DEFAULT_WINDOW_SIZE - windowSize); + DataFrame dataFrame = new DataFrame(stream.getId(), data, true); + stream.data(dataFrame, Callback.Adapter.INSTANCE); + return null; + } + else + { + // For every stream, send down half the window size of data. + MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false); + stream.headers(responseFrame, Callback.Adapter.INSTANCE); + DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(windowSize / 2), true); + stream.data(dataFrame, Callback.Adapter.INSTANCE); + return null; + } } }); Session session = newClient(new Session.Listener.Adapter()); - Map<Integer, Integer> settings = new HashMap<>(); - settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize); - session.settings(new SettingsFrame(settings, false), Callback.Adapter.INSTANCE); - - Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); - - final AtomicReference<Callback> callbackRef1 = new AtomicReference<>(); - final AtomicReference<Callback> callbackRef2 = new AtomicReference<>(); - - // First request will consume half the session window. - MetaData.Request request1 = newRequest("GET", new HttpFields()); + // First request is just to consume the session window. + final CountDownLatch prepareLatch = new CountDownLatch(1); + MetaData.Request request1 = newRequest("POST", new HttpFields()); session.newStream(new HeadersFrame(0, request1, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() { @Override public void onData(Stream stream, DataFrame frame, Callback callback) { - // Do not consume it to stall flow control. - callbackRef1.set(callback); + // Do not consume the data to reduce the session window. + if (frame.isEndStream()) + prepareLatch.countDown(); } }); + Assert.assertTrue(prepareLatch.await(5, TimeUnit.SECONDS)); - // Second request will consume the session window, which is now stalled. - // A third request will not be able to receive data. + final AtomicReference<Callback> callbackRef2 = new AtomicReference<>(); + final AtomicReference<Callback> callbackRef3 = new AtomicReference<>(); + + // Second request will consume half the session window. MetaData.Request request2 = newRequest("GET", new HttpFields()); session.newStream(new HeadersFrame(0, request2, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() { @@ -392,10 +394,23 @@ public class FlowControlTest extends AbstractTest } }); - // Third request is now stalled. - final CountDownLatch latch = new CountDownLatch(1); + // Third request will consume the session window, which is now stalled. + // A fourth request will not be able to receive data. MetaData.Request request3 = newRequest("GET", new HttpFields()); session.newStream(new HeadersFrame(0, request3, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + // Do not consume it to stall flow control. + callbackRef3.set(callback); + } + }); + + // Fourth request is now stalled. + final CountDownLatch latch = new CountDownLatch(1); + MetaData.Request request4 = newRequest("GET", new HttpFields()); + session.newStream(new HeadersFrame(0, request4, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() { @Override public void onData(Stream stream, DataFrame frame, Callback callback) @@ -409,9 +424,9 @@ public class FlowControlTest extends AbstractTest // Verify that the data does not arrive because the server session is stalled. Assert.assertFalse(latch.await(1, TimeUnit.SECONDS)); - // Consume the data of the second response. + // Consume the data of the third response. // This will open up the session window, allowing the third stream to send data. - Callback callback2 = callbackRef2.getAndSet(null); + Callback callback2 = callbackRef3.getAndSet(null); if (callback2 != null) callback2.succeeded(); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java index d4087435b33..4d3f681003e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java @@ -22,6 +22,8 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame; public interface FlowControl { + public static int DEFAULT_WINDOW_SIZE = 65535; + public void onNewStream(IStream stream); public int getInitialWindowSize(); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index 8f69833c527..91cc53a640a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -54,10 +54,7 @@ public class HTTP2FlowControl implements FlowControl this.initialWindowSize = initialWindowSize; int delta = initialWindowSize - windowSize; - // Update the session's window size. - session.onUpdateWindowSize(null, new WindowUpdateFrame(0, delta)); - - // Update the streams' window size. + // SPEC: updates of the initial window size only affect stream windows, not session's. for (Stream stream : session.getStreams()) session.onUpdateWindowSize((IStream)stream, new WindowUpdateFrame(stream.getId(), delta)); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 1852df83fb6..4148a70e453 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -213,7 +213,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (settings.containsKey(SettingsFrame.MAX_FRAME_SIZE)) { int maxFrameSize = settings.get(SettingsFrame.MAX_FRAME_SIZE); - // Spec: check the max frame size is sane. + // SPEC: check the max frame size is sane. if (maxFrameSize < Frame.DEFAULT_MAX_LENGTH || maxFrameSize > Frame.MAX_MAX_LENGTH) { onConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_settings_max_frame_size"); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 17eba76fd0a..cb238babfd9 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.server; import java.util.concurrent.Executor; +import org.eclipse.jetty.http2.FlowControl; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.ISession; @@ -36,7 +37,7 @@ import org.eclipse.jetty.server.Connector; public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory { private int maxHeaderTableSize = 4096; - private int initialWindowSize = 65535; + private int initialWindowSize = FlowControl.DEFAULT_WINDOW_SIZE; private int maxConcurrentStreams = -1; public AbstractHTTP2ServerConnectionFactory() From d26a003d4c979a9e7abb2afed229de242e54f95b Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 11 Aug 2014 23:46:00 +0200 Subject: [PATCH 224/269] Removed configuration for SPDY/2. --- .../src/main/config/etc/jetty-spdy.xml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml index fbaca7d5ef7..fcb9ce34734 100644 --- a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml +++ b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml @@ -42,10 +42,6 @@ <Set name="maxAssociatedResources">32</Set> </New> - <!-- =========================================================== --> - <!-- Add a SPDY/HTTPS Connector factory --> - <!-- =========================================================== --> - <!-- SPDY/3 Connection factory --> <Call name="addConnectionFactory"> <Arg> @@ -61,17 +57,4 @@ </Arg> </Call> - <!-- SPDY/2 Connection factory --> - <Call name="addConnectionFactory"> - <Arg> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">2</Arg> - <Arg name="config"><Ref refid="sslHttpConfig"/></Arg> - <!-- Set the initial window size for this SPDY connector. --> - <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> - <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set> - </New> - </Arg> - </Call> - </Configure> From d2fa4dca603f9f4af0f99280c1b8a5e6d6efae8b Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 11 Aug 2014 23:59:26 +0200 Subject: [PATCH 225/269] Introduced configuration properties for ALPN/NPN advertised protocols. No more need to copy protonego-alpn.xml to a jetty.base to specify which protocols are advertised. Instead, simply specify: protonego.protocols=h2-14,http/1.1 protonego.defaultProtocol=http/1.1 in start.ini (in the example above for http2). --- .../src/main/config/etc/protonego-alpn.xml | 7 +++++-- .../alpn/server/ALPNServerConnectionFactory.java | 4 ++-- .../src/main/resources/modules/ssl-protonego.mod | 2 +- .../src/main/config/modules/http2.mod | 5 +++++ .../src/main/config/etc/protonego-npn.xml | 15 +++++++-------- .../npn/server/NPNServerConnectionFactory.java | 4 ++-- .../NegotiatingServerConnectionFactory.java | 15 ++++++--------- .../src/main/config/modules/spdy.mod | 7 +++++-- 8 files changed, 33 insertions(+), 26 deletions(-) diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml index 657f8836e37..e3a15f29f04 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml +++ b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml @@ -15,9 +15,12 @@ <Call name="addConnectionFactory"> <Arg> <New id="protonego" class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory"> - <Arg name="protocols"> - <Array type="String"></Array> + <Arg type="String"> + <Property name="protonego.protocols" default="http/1.1" /> </Arg> + <Set name="defaultProtocol"> + <Property name="protonego.defaultProtocol" default="http/1.1" /> + </Set> </New> </Arg> </Call> diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index 3a0e50853a5..fdceb842fac 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -34,9 +34,9 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact { private static final Logger LOG = Log.getLogger(ALPNServerConnectionFactory.class); - public ALPNServerConnectionFactory() + public ALPNServerConnectionFactory(String protocols) { - this(new String[]{}); + this(protocols.split(",")); } public ALPNServerConnectionFactory(@Name("protocols") String... protocols) diff --git a/jetty-distribution/src/main/resources/modules/ssl-protonego.mod b/jetty-distribution/src/main/resources/modules/ssl-protonego.mod index 4a348a68297..ef4e50412cd 100644 --- a/jetty-distribution/src/main/resources/modules/ssl-protonego.mod +++ b/jetty-distribution/src/main/resources/modules/ssl-protonego.mod @@ -1,5 +1,5 @@ # -# SSL Protonegotiate module +# SSL Protocol Negotiatiation Module # [depend] diff --git a/jetty-http2/http2-server/src/main/config/modules/http2.mod b/jetty-http2/http2-server/src/main/config/modules/http2.mod index f1a43941a97..873e645f051 100644 --- a/jetty-http2/http2-server/src/main/config/modules/http2.mod +++ b/jetty-http2/http2-server/src/main/config/modules/http2.mod @@ -14,3 +14,8 @@ etc/jetty-http2.xml [ini-template] ## HTTP2 Configuration +# Advertised protocols +protonego.protocols=h2-14,http/1.1 +protonego.defaultProtocol=http/1.1 + +# http2.maxConcurrentStreams=1024 diff --git a/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml b/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml index 2a24f6ca2d4..56b8d0bd265 100644 --- a/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml +++ b/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml @@ -16,18 +16,17 @@ <Call name="addConnectionFactory"> <Arg> <New id="protonego" class="org.eclipse.jetty.npn.server.NPNServerConnectionFactory"> - <Arg name="protocols"> - <Array type="String"> - </Array> + <Arg type="String"> + <Property name="protonego.protocols" default="http/1.1" /> </Arg> + <Set name="defaultProtocol"> + <Property name="protonego.defaultProtocol" default="http/1.1" /> + </Set> </New> </Arg> </Call> - <!-- =========================================================== --> - <!-- Enables NPN debugging on System.err --> - <!-- =========================================================== - <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set> - --> + <!-- Enables NPN debugging on System.err --> + <!--<Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set>--> </Configure> diff --git a/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java index 39da0c404c9..f62f82c1a6c 100644 --- a/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java +++ b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java @@ -34,9 +34,9 @@ public class NPNServerConnectionFactory extends NegotiatingServerConnectionFacto { private static final Logger LOG = Log.getLogger(NPNServerConnectionFactory.class); - public NPNServerConnectionFactory() + public NPNServerConnectionFactory(String protocols) { - this(new String[]{}); + this(protocols.split(",")); } public NPNServerConnectionFactory(@Name("protocols") String... protocols) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java index 2daafb80f48..fa7ed65fc27 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java @@ -19,10 +19,8 @@ package org.eclipse.jetty.server; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import java.util.List; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.AbstractConnection; @@ -60,7 +58,10 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect public NegotiatingServerConnectionFactory(String protocol, String... protocols) { super(protocol); - this.protocols = new ArrayList<String>(Arrays.asList(protocols)); + this.protocols = new ArrayList<>(); + // Trim the values, as they may come from XML configuration. + for (String p : protocols) + this.protocols.add(p.trim()); } public String getDefaultProtocol() @@ -70,7 +71,8 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect public void setDefaultProtocol(String defaultProtocol) { - this.defaultProtocol = defaultProtocol; + // Trim the value, as it may come from XML configuration. + this.defaultProtocol = defaultProtocol.trim(); } public List<String> getProtocols() @@ -78,11 +80,6 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect return protocols; } - public void adProtocol(String protocol) - { - protocols.add(protocol); - } - @Override public Connection newConnection(Connector connector, EndPoint endPoint) { diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod index cb4cf971c7d..aa224c620cd 100644 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod +++ b/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod @@ -15,5 +15,8 @@ etc/jetty-spdy.xml [ini-template] ## SPDY Configuration -# Initial Window Size for SPDY -#spdy.initialWindowSize=65536 +# Advertised protocols +protonego.protocols=spdy/3,http/1.1 +protonego.defaultProtocol=http/1.1 + +# spdy.initialWindowSize=65536 From 4f4c3604a299440d40d6269ec04210594c0931f4 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 12 Aug 2014 16:27:33 +0200 Subject: [PATCH 226/269] Made the test more reliable. --- .../java/org/eclipse/jetty/http2/client/StreamResetTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java index abb177bb74c..8d14943322d 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java @@ -34,6 +34,7 @@ import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FutureCallback; import org.eclipse.jetty.util.FuturePromise; import org.junit.Assert; import org.junit.Test; @@ -52,7 +53,9 @@ public class StreamResetTest extends AbstractTest client.newStream(requestFrame, promise, new Stream.Listener.Adapter()); Stream stream = promise.get(5, TimeUnit.SECONDS); ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCodes.CANCEL_STREAM_ERROR); - stream.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); + FutureCallback resetCallback = new FutureCallback(); + stream.getSession().reset(resetFrame, resetCallback); + resetCallback.get(5, TimeUnit.SECONDS); // After reset the stream should be gone. Assert.assertEquals(0, client.getStreams().size()); } From e147ce9528d4856eb3cd8b85639d2044fefdca9e Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 12 Aug 2014 16:37:41 +0200 Subject: [PATCH 227/269] Updated flow control implementation to detect when senders exceed allowed windows. --- .../client/HTTP2ClientConnectionFactory.java | 23 ++++- .../jetty/http2/client/FlowControlTest.java | 93 +++++++++++++++++- .../org/eclipse/jetty/http2/FlowControl.java | 4 +- .../eclipse/jetty/http2/HTTP2FlowControl.java | 63 ++++++------ .../org/eclipse/jetty/http2/HTTP2Flusher.java | 4 +- .../org/eclipse/jetty/http2/HTTP2Session.java | 97 ++++++++++++------- .../org/eclipse/jetty/http2/HTTP2Stream.java | 39 ++++++-- .../org/eclipse/jetty/http2/ISession.java | 10 +- .../java/org/eclipse/jetty/http2/IStream.java | 6 +- .../org/eclipse/jetty/http2/frames/Frame.java | 1 + .../eclipse/jetty/http2/frames/FrameType.java | 4 +- .../jetty/http2/frames/PrefaceFrame.java | 34 +++++++ .../jetty/http2/frames/SettingsFrame.java | 12 --- .../jetty/http2/generator/Generator.java | 1 + .../http2/generator/PrefaceGenerator.java | 39 ++++++++ .../http2/generator/SettingsGenerator.java | 8 +- .../jetty/http2/parser/PrefaceParser.java | 11 +-- .../frames/SettingsGenerateParseTest.java | 6 +- .../AbstractHTTP2ServerConnectionFactory.java | 12 +-- .../server/HTTP2ServerConnectionFactory.java | 2 +- .../http2/server/HTTP2ServerSession.java | 4 +- .../jetty/http2/server/HTTP2ServerTest.java | 10 +- 22 files changed, 356 insertions(+), 127 deletions(-) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index fd2b41b108a..25a182b4186 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -28,7 +28,9 @@ import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.HTTP2FlowControl; import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.frames.PrefaceFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; @@ -48,6 +50,8 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener"; public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise"; + private int initialSessionWindow = FlowControl.DEFAULT_WINDOW_SIZE; + @Override public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException { @@ -65,6 +69,16 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory return new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, 8192, promise, listener); } + public int getInitialSessionWindow() + { + return initialSessionWindow; + } + + public void setInitialSessionWindow(int initialSessionWindow) + { + this.initialSessionWindow = initialSessionWindow; + } + private class HTTP2ClientConnection extends HTTP2Connection implements Callback { private final HTTP2Client client; @@ -86,7 +100,14 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory Map<Integer, Integer> settings = listener.onPreface(getSession()); if (settings == null) settings = Collections.emptyMap(); - getSession().settings(new SettingsFrame(settings, false, true), this); + + PrefaceFrame prefaceFrame = new PrefaceFrame(); + SettingsFrame settingsFrame = new SettingsFrame(settings, false); + int windowDelta = getInitialSessionWindow() - FlowControl.DEFAULT_WINDOW_SIZE; + if (windowDelta > 0) + getSession().control(null, this, prefaceFrame, settingsFrame, new WindowUpdateFrame(0, windowDelta)); + else + getSession().control(null, this, prefaceFrame, settingsFrame); } @Override diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java index f92b36021b0..7ce625d6ea6 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlTest.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.client; import java.nio.ByteBuffer; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.CountDownLatch; @@ -32,13 +33,18 @@ import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.FlowControl; +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; @@ -474,7 +480,7 @@ public class FlowControlTest extends AbstractTest } }); - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(latch.await(15, TimeUnit.SECONDS)); Assert.assertArrayEquals(data, bytes); } @@ -617,4 +623,89 @@ public class FlowControlTest extends AbstractTest responseContent.flip(); Assert.assertArrayEquals(requestData, responseData); } + + @Test + public void testClientExceedingSessionWindow() throws Exception + { + // On server, we don't consume the data. + startServer(new ServerSessionListener.Adapter()); + + final CountDownLatch closeLatch = new CountDownLatch(1); + Session session = newClient(new Session.Listener.Adapter() + { + @Override + public void onClose(Session session, GoAwayFrame frame) + { + if (frame.getError() == ErrorCodes.FLOW_CONTROL_ERROR) + closeLatch.countDown(); + } + }); + + // Consume the whole session and stream window. + MetaData.Request metaData = newRequest("POST", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, false); + FuturePromise<Stream> streamPromise = new FuturePromise<>(); + session.newStream(requestFrame, streamPromise, new Stream.Listener.Adapter()); + Stream stream = streamPromise.get(5, TimeUnit.SECONDS); + ByteBuffer data = ByteBuffer.allocate(FlowControl.DEFAULT_WINDOW_SIZE); + stream.data(new DataFrame(stream.getId(), data, false), Callback.Adapter.INSTANCE); + + // Now the client is supposed to not send more frames, but what if it does ? + HTTP2Session http2Session = (HTTP2Session)session; + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(connector.getByteBufferPool()); + ByteBuffer extraData = ByteBuffer.allocate(1024); + http2Session.getGenerator().data(lease, new DataFrame(stream.getId(), extraData, true), extraData.remaining()); + List<ByteBuffer> buffers = lease.getByteBuffers(); + http2Session.getEndPoint().write(Callback.Adapter.INSTANCE, buffers.toArray(new ByteBuffer[buffers.size()])); + + // Expect the connection to be closed. + Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testClientExceedingStreamWindow() throws Exception + { + // On server, we don't consume the data. + startServer(new ServerSessionListener.Adapter() + { + @Override + public Map<Integer, Integer> onPreface(Session session) + { + // Enlarge the session window. + ((ISession)session).updateRecvWindow(FlowControl.DEFAULT_WINDOW_SIZE); + return super.onPreface(session); + } + }); + + final CountDownLatch closeLatch = new CountDownLatch(1); + Session session = newClient(new Session.Listener.Adapter() + { + @Override + public void onClose(Session session, GoAwayFrame frame) + { + if (frame.getError() == ErrorCodes.FLOW_CONTROL_ERROR) + closeLatch.countDown(); + } + }); + + // Consume the whole stream window. + MetaData.Request metaData = newRequest("POST", new HttpFields()); + HeadersFrame requestFrame = new HeadersFrame(0, metaData, null, false); + FuturePromise<Stream> streamPromise = new FuturePromise<>(); + session.newStream(requestFrame, streamPromise, new Stream.Listener.Adapter()); + Stream stream = streamPromise.get(5, TimeUnit.SECONDS); + ByteBuffer data = ByteBuffer.allocate(FlowControl.DEFAULT_WINDOW_SIZE); + stream.data(new DataFrame(stream.getId(), data, false), Callback.Adapter.INSTANCE); + + // Now the client is supposed to not send more frames, but what if it does ? + HTTP2Session http2Session = (HTTP2Session)session; + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(connector.getByteBufferPool()); + ByteBuffer extraData = ByteBuffer.allocate(1024); + http2Session.getGenerator().data(lease, new DataFrame(stream.getId(), extraData, true), extraData.remaining()); + List<ByteBuffer> buffers = lease.getByteBuffers(); + http2Session.getEndPoint().write(Callback.Adapter.INSTANCE, buffers.toArray(new ByteBuffer[buffers.size()])); + + // Expect the connection to be closed. + Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java index 4d3f681003e..1126f74b324 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java @@ -26,9 +26,7 @@ public interface FlowControl public void onNewStream(IStream stream); - public int getInitialWindowSize(); - - public void updateInitialWindowSize(ISession session, int initialWindowSize); + public void updateInitialStreamWindow(ISession session, int initialStreamWindow); public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index 91cc53a640a..dd426fb876b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.http2; import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; @@ -28,35 +29,30 @@ public class HTTP2FlowControl implements FlowControl { private static final Logger LOG = Log.getLogger(HTTP2FlowControl.class); - private volatile int initialWindowSize; + private int initialStreamWindow; - public HTTP2FlowControl(int initialWindowSize) + public HTTP2FlowControl(int initialStreamWindow) { - this.initialWindowSize = initialWindowSize; + this.initialStreamWindow = initialStreamWindow; } @Override public void onNewStream(IStream stream) { - stream.updateWindowSize(initialWindowSize); + stream.updateSendWindow(initialStreamWindow); + stream.updateRecvWindow(FlowControl.DEFAULT_WINDOW_SIZE); } @Override - public int getInitialWindowSize() + public void updateInitialStreamWindow(ISession session, int initialStreamWindow) { - return initialWindowSize; - } - - @Override - public void updateInitialWindowSize(ISession session, int initialWindowSize) - { - int windowSize = this.initialWindowSize; - this.initialWindowSize = initialWindowSize; - int delta = initialWindowSize - windowSize; + int initialWindow = this.initialStreamWindow; + this.initialStreamWindow = initialStreamWindow; + int delta = initialStreamWindow - initialWindow; // SPEC: updates of the initial window size only affect stream windows, not session's. for (Stream stream : session.getStreams()) - session.onUpdateWindowSize((IStream)stream, new WindowUpdateFrame(stream.getId(), delta)); + session.onWindowUpdate((IStream)stream, new WindowUpdateFrame(stream.getId(), delta)); } @Override @@ -68,22 +64,30 @@ public class HTTP2FlowControl implements FlowControl // The stream may have been reset concurrently. if (stream != null) { - int oldSize = stream.updateWindowSize(delta); + int oldSize = stream.updateSendWindow(delta); if (LOG.isDebugEnabled()) - LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize + delta, stream); + LOG.debug("Updated stream send window {} -> {} for {}", oldSize, oldSize + delta, stream); } } else { - int oldSize = session.updateWindowSize(delta); + int oldSize = session.updateSendWindow(delta); if (LOG.isDebugEnabled()) - LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize + delta, session); + LOG.debug("Updated session send window {} -> {} for {}", oldSize, oldSize + delta, session); } } @Override public void onDataReceived(IStream stream, int length) { + ISession session = stream.getSession(); + int oldSize = session.updateRecvWindow(-length); + if (LOG.isDebugEnabled()) + LOG.debug("Updated session recv window {} -> {} for {}", oldSize, oldSize - length, session); + + oldSize = stream.updateRecvWindow(-length); + if (LOG.isDebugEnabled()) + LOG.debug("Updated stream recv window {} -> {} for {}", oldSize, oldSize - length, stream); } @Override @@ -95,13 +99,17 @@ public class HTTP2FlowControl implements FlowControl // Other policies may send the WindowUpdate only upon reaching a threshold. if (LOG.isDebugEnabled()) - LOG.debug("Data consumed, increasing window by {} for {}", length, stream); + LOG.debug("Data consumed, increasing windows by {} for {}", length, stream); if (length > 0) { - // Negative streamId allow for generation of bytes for both stream and session + ISession session = stream.getSession(); + session.updateRecvWindow(length); + stream.updateRecvWindow(length); + + // Negative streamId allow for generation of bytes for both stream and session. WindowUpdateFrame frame = new WindowUpdateFrame(-stream.getId(), length); - stream.getSession().control(stream, frame, Callback.Adapter.INSTANCE); + session.control(stream, Callback.Adapter.INSTANCE, frame, Frame.EMPTY_ARRAY); } } @@ -111,17 +119,14 @@ public class HTTP2FlowControl implements FlowControl if (length == 0) return; - if (LOG.isDebugEnabled()) - LOG.debug("Data sending, decreasing windows by {}", length); - ISession session = stream.getSession(); - int oldSize = session.updateWindowSize(-length); + int oldSize = session.updateSendWindow(-length); if (LOG.isDebugEnabled()) - LOG.debug("Updated session window {} -> {} for {}", oldSize, oldSize - length, session); + LOG.debug("Updated session send window {} -> {} for {}", oldSize, oldSize - length, session); - oldSize = stream.updateWindowSize(-length); + oldSize = stream.updateSendWindow(-length); if (LOG.isDebugEnabled()) - LOG.debug("Updated stream window {} -> {} for {}", oldSize, oldSize - length, stream); + LOG.debug("Updated stream send window {} -> {} for {}", oldSize, oldSize - length, stream); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java index 78848c5279b..ec58db8c39d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java @@ -139,7 +139,7 @@ public class HTTP2Flusher extends IteratingCallback // Now the window sizes cannot change. // Window updates that happen concurrently will // be queued and processed on the next iteration. - int sessionWindow = session.getWindowSize(); + int sessionWindow = session.getSendWindow(); int index = 0; int size = frames.size(); @@ -165,7 +165,7 @@ public class HTTP2Flusher extends IteratingCallback Integer streamWindow = streams.get(stream); if (streamWindow == null) { - streamWindow = stream.getWindowSize(); + streamWindow = stream.getSendWindow(); streams.put(stream, streamWindow); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 4148a70e453..6d2f2716c05 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -72,7 +72,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final AtomicInteger lastStreamId = new AtomicInteger(); private final AtomicInteger localStreamCount = new AtomicInteger(); private final AtomicInteger remoteStreamCount = new AtomicInteger(); - private final AtomicInteger windowSize = new AtomicInteger(); + private final AtomicInteger sendWindow = new AtomicInteger(); + private final AtomicInteger recvWindow = new AtomicInteger(); private final AtomicBoolean closed = new AtomicBoolean(); private final Scheduler scheduler; private final EndPoint endPoint; @@ -94,7 +95,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener this.maxLocalStreams = maxStreams; this.maxRemoteStreams = maxStreams; this.streamIds.set(initialStreamId); - this.windowSize.set(flowControl.getInitialWindowSize()); + this.sendWindow.set(FlowControl.DEFAULT_WINDOW_SIZE); + this.recvWindow.set(FlowControl.DEFAULT_WINDOW_SIZE); } public FlowControl getFlowControl() @@ -132,9 +134,17 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (stream != null) { stream.updateClose(frame.isEndStream(), false); + // The flow control length includes the padding bytes. final int flowControlLength = frame.remaining() + frame.padding(); flowControl.onDataReceived(stream, flowControlLength); + + if (getRecvWindow() < 0) + { + close(ErrorCodes.FLOW_CONTROL_ERROR, "session_window_exceeded", disconnectOnFailure); + return false; + } + boolean result = stream.process(frame, new Callback.Adapter() { @Override @@ -143,6 +153,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flowControl.onDataConsumed(stream, flowControlLength); } }); + if (stream.isClosed()) removeStream(stream, false); return result; @@ -207,8 +218,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } if (settings.containsKey(SettingsFrame.INITIAL_WINDOW_SIZE)) { - int windowSize = settings.get(SettingsFrame.INITIAL_WINDOW_SIZE); - flowControl.updateInitialWindowSize(this, windowSize); + int initialWindow = settings.get(SettingsFrame.INITIAL_WINDOW_SIZE); + flowControl.updateInitialStreamWindow(this, initialWindow); } if (settings.containsKey(SettingsFrame.MAX_FRAME_SIZE)) { @@ -250,7 +261,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener else { PingFrame reply = new PingFrame(frame.getPayload(), true); - control(null, reply, disconnectOnFailure()); + control(null, disconnectOnFailure(), reply); } return false; } @@ -297,11 +308,11 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { IStream stream = getStream(streamId); if (stream != null) - onUpdateWindowSize(stream, frame); + onWindowUpdate(stream, frame); } else { - onUpdateWindowSize(null, frame); + onWindowUpdate(null, frame); } return false; } @@ -340,7 +351,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void settings(SettingsFrame frame, Callback callback) { - control(null, frame, callback); + control(null, callback, frame); } @Override @@ -349,13 +360,13 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (frame.isReply()) callback.failed(new IllegalArgumentException()); else - control(null, frame, callback); + control(null, callback, frame); } @Override public void reset(ResetFrame frame, Callback callback) { - control(getStream(frame.getStreamId()), frame, callback); + control(getStream(frame.getStreamId()), callback, frame); } @Override @@ -367,25 +378,33 @@ public abstract class HTTP2Session implements ISession, Parser.Listener GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); if (LOG.isDebugEnabled()) LOG.debug("Sending {}: {}", frame.getType(), reason); - control(null, frame, callback); + control(null, callback, frame); } } - @Override - public void control(IStream stream, Frame frame, Callback callback) + private void control(IStream stream, Callback callback, Frame frame) { - // We want to generate as late as possible to allow re-prioritization. - frame(new ControlEntry(frame, stream, callback)); + control(stream, callback, frame, Frame.EMPTY_ARRAY); } @Override - public void data(IStream stream, DataFrame frame, Callback callback) + public void control(IStream stream, Callback callback, Frame frame, Frame... frames) { // We want to generate as late as possible to allow re-prioritization. - frame(new DataEntry(frame, stream, callback)); + int length = frames.length; + frame(new ControlEntry(frame, stream, callback), length == 0); + for (int i = 1; i <= length; ++i) + frame(new ControlEntry(frames[i - 1], stream, callback), i == length); } - private void frame(HTTP2Flusher.Entry entry) + @Override + public void data(IStream stream, Callback callback, DataFrame frame) + { + // We want to generate as late as possible to allow re-prioritization. + frame(new DataEntry(frame, stream, callback), true); + } + + private void frame(HTTP2Flusher.Entry entry, boolean flush) { if (LOG.isDebugEnabled()) LOG.debug("Sending {}", entry.frame); @@ -394,7 +413,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.prepend(entry); else flusher.append(entry); - flusher.iterate(); + if (flush) + flusher.iterate(); } protected IStream createLocalStream(HeadersFrame frame, Promise<Stream> promise) @@ -502,19 +522,30 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return streams.get(streamId); } - protected int getWindowSize() + protected int getSendWindow() { - return windowSize.get(); + return sendWindow.get(); + } + + protected int getRecvWindow() + { + return recvWindow.get(); } @Override - public int updateWindowSize(int delta) + public int updateSendWindow(int delta) { - return windowSize.getAndAdd(delta); + return sendWindow.getAndAdd(delta); } @Override - public void onUpdateWindowSize(IStream stream, WindowUpdateFrame frame) + public int updateRecvWindow(int delta) + { + return recvWindow.getAndAdd(delta); + } + + @Override + public void onWindowUpdate(IStream stream, WindowUpdateFrame frame) { // WindowUpdateFrames arrive concurrently with writes. // Increasing (or reducing) the window size concurrently @@ -618,8 +649,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public String toString() { - return String.format("%s@%x{queueSize=%d,windowSize=%s,streams=%d}", getClass().getSimpleName(), - hashCode(), flusher.getQueueSize(), windowSize, streams.size()); + return String.format("%s@%x{queueSize=%d,sendWindow=%s,recvWindow=%s,streams=%d}", getClass().getSimpleName(), + hashCode(), flusher.getQueueSize(), sendWindow, recvWindow, streams.size()); } private class ControlEntry extends HTTP2Flusher.Entry @@ -697,19 +728,19 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { int flowControlLength = dataRemaining(); - int sessionWindowSize = getWindowSize(); - if (sessionWindowSize < 0) + int sessionSendWindow = getSendWindow(); + if (sessionSendWindow < 0) throw new IllegalStateException(); - int streamWindowSize = stream.getWindowSize(); - if (streamWindowSize < 0) + int streamSendWindow = stream.getSendWindow(); + if (streamSendWindow < 0) throw new IllegalStateException(); - int windowSize = Math.min(streamWindowSize, sessionWindowSize); + int window = Math.min(streamSendWindow, sessionSendWindow); - int length = this.length = Math.min(flowControlLength, windowSize); + int length = this.length = Math.min(flowControlLength, window); if (LOG.isDebugEnabled()) - LOG.debug("Generated {}, length/window={}/{}", frame, length, windowSize); + LOG.debug("Generated {}, length/window={}/{}", frame, length, window); generator.data(lease, (DataFrame)frame, length); flowControl.onDataSending(stream, length); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index d095e2296f9..bd7668eeb93 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -49,7 +49,8 @@ public class HTTP2Stream extends IdleTimeout implements IStream }; private final AtomicReference<ConcurrentMap<String, Object>> attributes = new AtomicReference<>(); private final AtomicReference<CloseState> closeState = new AtomicReference<>(CloseState.NOT_CLOSED); - private final AtomicInteger windowSize = new AtomicInteger(); + private final AtomicInteger sendWindow = new AtomicInteger(); + private final AtomicInteger recvWindow = new AtomicInteger(); private final ISession session; private final HeadersFrame frame; private volatile Listener listener; @@ -77,13 +78,13 @@ public class HTTP2Stream extends IdleTimeout implements IStream @Override public void headers(HeadersFrame frame, Callback callback) { - session.control(this, frame, callback); + session.control(this, callback, frame, Frame.EMPTY_ARRAY); } @Override public void data(DataFrame frame, Callback callback) { - session.data(this, frame, callback); + session.data(this, callback, frame); } @Override @@ -175,6 +176,15 @@ public class HTTP2Stream extends IdleTimeout implements IStream // TODO: handle cases where: // TODO: A) stream already remotely close. // TODO: B) DATA before HEADERS. + + if (getRecvWindow() < 0) + { + // It's a bad client, it does not deserve to be + // treated gently by just resetting the stream. + session.close(ErrorCodes.FLOW_CONTROL_ERROR, "stream_window_exceeded", disconnectOnFailure); + return false; + } + notifyData(this, (DataFrame)frame, callback); return false; } @@ -237,15 +247,26 @@ public class HTTP2Stream extends IdleTimeout implements IStream } @Override - public int getWindowSize() + public int getSendWindow() { - return windowSize.get(); + return sendWindow.get(); + } + + protected int getRecvWindow() + { + return recvWindow.get(); } @Override - public int updateWindowSize(int delta) + public int updateSendWindow(int delta) { - return windowSize.getAndAdd(delta); + return sendWindow.getAndAdd(delta); + } + + @Override + public int updateRecvWindow(int delta) + { + return recvWindow.getAndAdd(delta); } @Override @@ -288,8 +309,8 @@ public class HTTP2Stream extends IdleTimeout implements IStream @Override public String toString() { - return String.format("%s@%x{id=%d,windowSize=%s,reset=%b,%s}", getClass().getSimpleName(), - hashCode(), getId(), windowSize, reset, closeState); + return String.format("%s@%x{id=%d,sendWindow=%s,recvWindow=%s,reset=%b,%s}", getClass().getSimpleName(), + hashCode(), getId(), sendWindow, recvWindow, reset, closeState); } private enum CloseState diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index e9edfee0d33..d40ba0b1901 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -29,13 +29,15 @@ public interface ISession extends Session @Override public IStream getStream(int streamId); - public void control(IStream stream, Frame frame, Callback callback); + public void control(IStream stream, Callback callback, Frame frame, Frame... frames); - public void data(IStream stream, DataFrame frame, Callback callback); + public void data(IStream stream, Callback callback, DataFrame frame); - public int updateWindowSize(int delta); + public int updateSendWindow(int delta); - public void onUpdateWindowSize(IStream stream, WindowUpdateFrame frame); + public int updateRecvWindow(int delta); + + public void onWindowUpdate(IStream stream, WindowUpdateFrame frame); public void shutdown(); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index fa709c4f48f..0139f12d0fe 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -44,9 +44,11 @@ public interface IStream extends Stream */ public void updateClose(boolean update, boolean local); - public int getWindowSize(); + public int getSendWindow(); - public int updateWindowSize(int delta); + public int updateSendWindow(int delta); + + public int updateRecvWindow(int delta); public void close(); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java index 4a6f36ed4e1..030d793fa86 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java @@ -23,6 +23,7 @@ public abstract class Frame public static final int HEADER_LENGTH = 9; public static final int DEFAULT_MAX_LENGTH = 0x40_00; public static final int MAX_MAX_LENGTH = 0xFF_FF_FF; + public static final Frame[] EMPTY_ARRAY = new Frame[0]; private final FrameType type; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java index 98b34bfef8a..9d61ac4f900 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java @@ -32,7 +32,9 @@ public enum FrameType PING(6), GO_AWAY(7), WINDOW_UPDATE(8), - CONTINUATION(9); + CONTINUATION(9), + // Synthetic frames only needed by the implementation. + PREFACE(10); public static FrameType from(int type) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java new file mode 100644 index 00000000000..db0840e186a --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java @@ -0,0 +1,34 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class PrefaceFrame extends Frame +{ + public static final byte[] PREFACE_BYTES = new byte[] + { + 0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54, + 0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a, + 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a + }; + + public PrefaceFrame() + { + super(FrameType.PREFACE); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java index f5f2a0b37e0..ef7a53b572e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -30,19 +30,12 @@ public class SettingsFrame extends Frame private final Map<Integer, Integer> settings; private final boolean reply; - private boolean preface; public SettingsFrame(Map<Integer, Integer> settings, boolean reply) - { - this(settings, reply, false); - } - - public SettingsFrame(Map<Integer, Integer> settings, boolean reply, boolean preface) { super(FrameType.SETTINGS); this.settings = settings; this.reply = reply; - this.preface = preface; } public Map<Integer, Integer> getSettings() @@ -54,9 +47,4 @@ public class SettingsFrame extends Frame { return reply; } - - public boolean isPreface() - { - return preface; - } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 105e4d61b98..bed1558477c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -54,6 +54,7 @@ public class Generator this.generators[FrameType.GO_AWAY.getType()] = new GoAwayGenerator(headerGenerator); this.generators[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateGenerator(headerGenerator); this.generators[FrameType.CONTINUATION.getType()] = null; // TODO + this.generators[FrameType.PREFACE.getType()] = new PrefaceGenerator(); this.dataGenerator = new DataGenerator(headerGenerator); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java new file mode 100644 index 00000000000..6df810e73b5 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java @@ -0,0 +1,39 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.PrefaceFrame; +import org.eclipse.jetty.io.ByteBufferPool; + +public class PrefaceGenerator extends FrameGenerator +{ + public PrefaceGenerator() + { + super(null); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame) + { + lease.append(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index 8430ddf170e..dde019225ff 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -25,7 +25,6 @@ import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.SettingsFrame; -import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.BufferUtil; @@ -40,14 +39,11 @@ public class SettingsGenerator extends FrameGenerator public void generate(ByteBufferPool.Lease lease, Frame frame) { SettingsFrame settingsFrame = (SettingsFrame)frame; - generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply(), settingsFrame.isPreface()); + generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply()); } - public void generateSettings(ByteBufferPool.Lease lease, Map<Integer, Integer> settings, boolean reply, boolean preface) + public void generateSettings(ByteBufferPool.Lease lease, Map<Integer, Integer> settings, boolean reply) { - if (preface) - lease.append(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); - // Two bytes for the identifier, four bytes for the value. int entryLength = 2 + 4; int length = entryLength * settings.size(); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java index 92e9d1e9060..b09924041f5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java @@ -21,17 +21,12 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.http2.ErrorCodes; +import org.eclipse.jetty.http2.frames.PrefaceFrame; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; public class PrefaceParser { - public static final byte[] PREFACE_BYTES = new byte[] - { - 0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54, - 0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a, - 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a - }; private static final Logger LOG = Log.getLogger(PrefaceParser.class); private final Parser.Listener listener; @@ -47,13 +42,13 @@ public class PrefaceParser while (buffer.hasRemaining()) { int currByte = buffer.get(); - if (currByte != PREFACE_BYTES[cursor]) + if (currByte != PrefaceFrame.PREFACE_BYTES[cursor]) { notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_preface"); return false; } ++cursor; - if (cursor == PREFACE_BYTES.length) + if (cursor == PrefaceFrame.PREFACE_BYTES.length) { cursor = 0; if (LOG.isDebugEnabled()) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index 9f976a0722a..c23674819ef 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -87,7 +87,7 @@ public class SettingsGenerateParseTest for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings, true, false); + generator.generateSettings(lease, settings, true); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -120,7 +120,7 @@ public class SettingsGenerateParseTest Map<Integer, Integer> settings1 = new HashMap<>(); settings1.put(13, 17); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings1, true, false); + generator.generateSettings(lease, settings1, true); // Modify the length of the frame to make it invalid ByteBuffer bytes = lease.getByteBuffers().get(0); bytes.putShort(1, (short)(bytes.getShort(1) - 1)); @@ -158,7 +158,7 @@ public class SettingsGenerateParseTest settings1.put(key, value); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings1, true, false); + generator.generateSettings(lease, settings1, true); for (ByteBuffer buffer : lease.getByteBuffers()) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index cb238babfd9..cd4c12254d3 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -37,7 +37,7 @@ import org.eclipse.jetty.server.Connector; public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory { private int maxHeaderTableSize = 4096; - private int initialWindowSize = FlowControl.DEFAULT_WINDOW_SIZE; + private int initialStreamWindow = FlowControl.DEFAULT_WINDOW_SIZE; private int maxConcurrentStreams = -1; public AbstractHTTP2ServerConnectionFactory() @@ -55,14 +55,14 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne this.maxHeaderTableSize = maxHeaderTableSize; } - public int getInitialWindowSize() + public int getInitialStreamWindow() { - return initialWindowSize; + return initialStreamWindow; } - public void setInitialWindowSize(int initialWindowSize) + public void setInitialStreamWindow(int initialStreamWindow) { - this.initialWindowSize = initialWindowSize; + this.initialStreamWindow = initialStreamWindow; } public int getMaxConcurrentStreams() @@ -82,7 +82,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne Generator generator = new Generator(connector.getByteBufferPool(), getMaxHeaderTableSize()); HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, generator, listener, - new HTTP2FlowControl(getInitialWindowSize()), getMaxConcurrentStreams()); + new HTTP2FlowControl(getInitialStreamWindow()), getMaxConcurrentStreams()); Parser parser = newServerParser(connector.getByteBufferPool(), session); HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(), diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 8b080691518..fb6403c4c21 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -80,7 +80,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF { Map<Integer, Integer> settings = new HashMap<>(); settings.put(SettingsFrame.HEADER_TABLE_SIZE, getMaxHeaderTableSize()); - settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialWindowSize()); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialStreamWindow()); int maxConcurrentStreams = getMaxConcurrentStreams(); if (maxConcurrentStreams >= 0) settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index 0bea5ad677c..a0df3ce9c1f 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; @@ -57,7 +58,8 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis if (settings == null) settings = Collections.emptyMap(); SettingsFrame frame = new SettingsFrame(settings, false); - settings(frame, disconnectOnFailure()); + // TODO: consider sending a WINDOW_UPDATE to enlarge the session send window of the client. + control(null, disconnectOnFailure(), frame, Frame.EMPTY_ARRAY); return false; } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 59100a75149..4befeb48029 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -44,10 +44,10 @@ import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; +import org.eclipse.jetty.http2.frames.PrefaceFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; -import org.eclipse.jetty.http2.parser.PrefaceParser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.server.HttpConfiguration; @@ -152,7 +152,7 @@ public class HTTP2ServerTest HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, request); - lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); + lease.prepend(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); try (Socket client = new Socket(host, port)) { @@ -215,7 +215,7 @@ public class HTTP2ServerTest HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, request); - lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); + lease.prepend(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); try (Socket client = new Socket(host, port)) { @@ -280,7 +280,7 @@ public class HTTP2ServerTest generator.control(lease, frame); // Modify the length of the frame to a wrong one. lease.getByteBuffers().get(0).putShort(0, (short)7); - lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); + lease.prepend(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); final CountDownLatch latch = new CountDownLatch(1); try (Socket client = new Socket(host, port)) @@ -320,7 +320,7 @@ public class HTTP2ServerTest generator.control(lease, frame); // Modify the streamId of the frame to non zero. lease.getByteBuffers().get(0).putInt(4, 1); - lease.prepend(ByteBuffer.wrap(PrefaceParser.PREFACE_BYTES), false); + lease.prepend(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); final CountDownLatch latch = new CountDownLatch(1); try (Socket client = new Socket(host, port)) From 814c84a21200220fe2e0d38140c362d2d7f1fea4 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 12 Aug 2014 17:11:41 +0200 Subject: [PATCH 228/269] Introduced configuration properties for ALPN/NPN advertised protocols. No more need to copy protonego-alpn.xml to a jetty.base to specify which protocols are advertised and in which order. Instead, simply specify: alpn.protocols=h2-14,http/1.1 alpn.defaultProtocol=http/1.1 in start.ini (in the example above for http2). --- .../src/main/config/etc/protonego-alpn.xml | 4 ++-- .../config/modules/protonego-impl/alpn.mod | 4 ++++ .../server/ALPNServerConnectionFactory.java | 4 ++-- .../main/resources/modules/ssl-protonego.mod | 2 +- .../src/main/config/modules/http2.mod | 4 ---- .../src/main/config/etc/protonego-npn.xml | 4 ++-- .../config/modules/protonego-impl/npn.mod | 4 ++++ .../server/NPNServerConnectionFactory.java | 2 +- .../NegotiatingServerConnectionFactory.java | 20 ++++++++++++++----- .../src/main/config/modules/spdy.mod | 7 ++----- 10 files changed, 33 insertions(+), 22 deletions(-) diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml index e3a15f29f04..6fb836fb537 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml +++ b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml @@ -16,10 +16,10 @@ <Arg> <New id="protonego" class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory"> <Arg type="String"> - <Property name="protonego.protocols" default="http/1.1" /> + <Property name="alpn.protocols" default="" /> </Arg> <Set name="defaultProtocol"> - <Property name="protonego.defaultProtocol" default="http/1.1" /> + <Property name="alpn.defaultProtocol" /> </Set> </New> </Arg> diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod index ca51179c269..cabaeba942b 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod @@ -31,3 +31,7 @@ lib/jetty-alpn-server-${jetty.version}.jar lib/ lib/alpn/ +[ini-template] +# alpn.protocols=h2-14,http/1.1 +# alpn.defaultProtocol=http/1.1 + diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index fdceb842fac..bc51d5e43dd 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -36,9 +36,9 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact public ALPNServerConnectionFactory(String protocols) { - this(protocols.split(",")); + this(protocols.trim().split(",", 0)); } - + public ALPNServerConnectionFactory(@Name("protocols") String... protocols) { super("alpn", protocols); diff --git a/jetty-distribution/src/main/resources/modules/ssl-protonego.mod b/jetty-distribution/src/main/resources/modules/ssl-protonego.mod index ef4e50412cd..b142c36d1b8 100644 --- a/jetty-distribution/src/main/resources/modules/ssl-protonego.mod +++ b/jetty-distribution/src/main/resources/modules/ssl-protonego.mod @@ -1,5 +1,5 @@ # -# SSL Protocol Negotiatiation Module +# SSL Protocol Negotiation Module # [depend] diff --git a/jetty-http2/http2-server/src/main/config/modules/http2.mod b/jetty-http2/http2-server/src/main/config/modules/http2.mod index 873e645f051..3caec47958e 100644 --- a/jetty-http2/http2-server/src/main/config/modules/http2.mod +++ b/jetty-http2/http2-server/src/main/config/modules/http2.mod @@ -14,8 +14,4 @@ etc/jetty-http2.xml [ini-template] ## HTTP2 Configuration -# Advertised protocols -protonego.protocols=h2-14,http/1.1 -protonego.defaultProtocol=http/1.1 - # http2.maxConcurrentStreams=1024 diff --git a/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml b/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml index 56b8d0bd265..ef887d10e30 100644 --- a/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml +++ b/jetty-npn/jetty-npn-server/src/main/config/etc/protonego-npn.xml @@ -17,10 +17,10 @@ <Arg> <New id="protonego" class="org.eclipse.jetty.npn.server.NPNServerConnectionFactory"> <Arg type="String"> - <Property name="protonego.protocols" default="http/1.1" /> + <Property name="npn.protocols" default="" /> </Arg> <Set name="defaultProtocol"> - <Property name="protonego.defaultProtocol" default="http/1.1" /> + <Property name="npn.defaultProtocol" /> </Set> </New> </Arg> diff --git a/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod index a1bbc46ee46..5fb129de2d8 100644 --- a/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod +++ b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn.mod @@ -30,3 +30,7 @@ lib/jetty-npn-server-${jetty.version}.jar [files] lib/ lib/npn/ + +[ini-template] +# npn.protocols=spdy/3,http/1.1 +# npn.defaultProtocol=http/1.1 diff --git a/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java index f62f82c1a6c..4cd87ca385a 100644 --- a/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java +++ b/jetty-npn/jetty-npn-server/src/main/java/org/eclipse/jetty/npn/server/NPNServerConnectionFactory.java @@ -36,7 +36,7 @@ public class NPNServerConnectionFactory extends NegotiatingServerConnectionFacto public NPNServerConnectionFactory(String protocols) { - this(protocols.split(",")); + this(protocols.trim().split(",", 0)); } public NPNServerConnectionFactory(@Name("protocols") String... protocols) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java index fa7ed65fc27..66bff06ba74 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java @@ -59,9 +59,16 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect { super(protocol); this.protocols = new ArrayList<>(); - // Trim the values, as they may come from XML configuration. - for (String p : protocols) - this.protocols.add(p.trim()); + if (protocols != null) + { + // Trim the values, as they may come from XML configuration. + for (String p : protocols) + { + p = p.trim(); + if (!p.isEmpty()) + this.protocols.add(p.trim()); + } + } } public String getDefaultProtocol() @@ -72,7 +79,8 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect public void setDefaultProtocol(String defaultProtocol) { // Trim the value, as it may come from XML configuration. - this.defaultProtocol = defaultProtocol.trim(); + String dft = defaultProtocol == null ? "" : defaultProtocol.trim(); + this.defaultProtocol = dft.isEmpty() ? null : dft; } public List<String> getProtocols() @@ -91,7 +99,9 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect while (i.hasNext()) { String protocol = i.next(); - if ("SSL".equalsIgnoreCase(protocol) || "alpn".equalsIgnoreCase("protocol")) + if ("ssl".equalsIgnoreCase(protocol) || + "alpn".equalsIgnoreCase(protocol) || + "npn".equalsIgnoreCase(protocol)) { i.remove(); } diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod index aa224c620cd..cb4cf971c7d 100644 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod +++ b/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod @@ -15,8 +15,5 @@ etc/jetty-spdy.xml [ini-template] ## SPDY Configuration -# Advertised protocols -protonego.protocols=spdy/3,http/1.1 -protonego.defaultProtocol=http/1.1 - -# spdy.initialWindowSize=65536 +# Initial Window Size for SPDY +#spdy.initialWindowSize=65536 From 20963c9c615c6763642befec79d49769859f63f2 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 12 Aug 2014 18:06:11 +0200 Subject: [PATCH 229/269] Refactored host and port to local variables. --- .../test/java/org/eclipse/jetty/http2/client/Client.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java index eea82ed21d7..283ae8e629a 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java @@ -47,13 +47,16 @@ public class Client client.addBean(sslContextFactory); client.start(); + String host = "webtide.com"; + int port = 443; + FuturePromise<Session> sessionPromise = new FuturePromise<>(); - client.connect(sslContextFactory, new InetSocketAddress("webtide.com", 443), new ServerSessionListener.Adapter(), sessionPromise); + client.connect(sslContextFactory, new InetSocketAddress(host, port), new ServerSessionListener.Adapter(), sessionPromise); Session session = sessionPromise.get(5, TimeUnit.SECONDS); HttpFields requestFields = new HttpFields(); requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION); - MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://webtide.com/"), HttpVersion.HTTP_2, requestFields); + MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields); HeadersFrame headersFrame = new HeadersFrame(0, metaData, null, true); final CountDownLatch latch = new CountDownLatch(1); session.newStream(headersFrame, new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() From 14dc4fade0745899b06994ec2c934a9bf38e7d2e Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 12 Aug 2014 22:32:17 +0200 Subject: [PATCH 230/269] Updated log statements to use debug() instead of info(). --- .../eclipse/jetty/server/AbstractConnector.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 893de2f9d62..3322fe89b73 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -24,7 +24,6 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -365,13 +364,15 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co if (old.getProtocol().equals(_defaultProtocol)) _defaultProtocol=null; removeBean(old); - LOG.info("{} removed {}",this,old); + if (LOG.isDebugEnabled()) + LOG.debug("{} removed {}", this, old); } _factories.put(key, factory); addBean(factory); if (_defaultProtocol==null) _defaultProtocol=factory.getProtocol(); - LOG.info("{} added {}",this,factory); + if (LOG.isDebugEnabled()) + LOG.debug("{} added {}", this, factory); } } @@ -381,14 +382,18 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co { String key=StringUtil.asciiToLowerCase(factory.getProtocol()); if (_factories.containsKey(key)) - LOG.info("{} addIfAbsent ignored {}",this,factory); + { + if (LOG.isDebugEnabled()) + LOG.debug("{} addIfAbsent ignored {}", this, factory); + } else { _factories.put(key, factory); addBean(factory); if (_defaultProtocol==null) _defaultProtocol=factory.getProtocol(); - LOG.info("{} addIfAbsent added {}",this,factory); + if (LOG.isDebugEnabled()) + LOG.debug("{} addIfAbsent added {}", this, factory); } } } From a97d4642abba9bea238f7d14218e8a6d56aeacb1 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 12 Aug 2014 23:01:03 +0200 Subject: [PATCH 231/269] Improved toString() methods for frames. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 19 +------------- .../jetty/http2/frames/GoAwayFrame.java | 25 +++++++++++++++++++ .../jetty/http2/frames/ResetFrame.java | 6 +++++ .../jetty/http2/frames/SettingsFrame.java | 6 +++++ .../jetty/http2/frames/WindowUpdateFrame.java | 2 +- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 6d2f2716c05..a217dd9f89c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.http2; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; @@ -48,7 +47,6 @@ import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Atomics; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.log.Log; @@ -271,7 +269,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { if (LOG.isDebugEnabled()) { - String reason = tryConvertPayload(frame.getPayload()); + String reason = frame.tryConvertPayload(); if (LOG.isDebugEnabled()) LOG.debug("Received {}: {}/'{}'", frame.getType(), frame.getError(), reason); } @@ -283,21 +281,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return false; } - private String tryConvertPayload(byte[] payload) - { - if (payload == null) - return ""; - ByteBuffer buffer = BufferUtil.toBuffer(payload); - try - { - return BufferUtil.toUTF8String(buffer); - } - catch (Throwable x) - { - return BufferUtil.toDetailString(buffer); - } - } - @Override public boolean onWindowUpdate(WindowUpdateFrame frame) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java index 6615c0f6589..482208f3113 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java @@ -18,6 +18,10 @@ package org.eclipse.jetty.http2.frames; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.BufferUtil; + public class GoAwayFrame extends Frame { private final int lastStreamId; @@ -46,4 +50,25 @@ public class GoAwayFrame extends Frame { return payload; } + + public String tryConvertPayload() + { + if (payload == null) + return ""; + ByteBuffer buffer = BufferUtil.toBuffer(payload); + try + { + return BufferUtil.toUTF8String(buffer); + } + catch (Throwable x) + { + return BufferUtil.toDetailString(buffer); + } + } + + @Override + public String toString() + { + return String.format("%s,%d/%s", super.toString(), error, tryConvertPayload()); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java index 55595e99f14..ee4faea163b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java @@ -39,4 +39,10 @@ public class ResetFrame extends Frame { return error; } + + @Override + public String toString() + { + return String.format("%s#%d,error=%d", super.toString(), streamId, error); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java index ef7a53b572e..9909d962988 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -47,4 +47,10 @@ public class SettingsFrame extends Frame { return reply; } + + @Override + public String toString() + { + return String.format("%s,reply=%b:%s", super.toString(), reply, settings); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java index b5909dfa831..3e0c9b1a4d3 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java @@ -43,6 +43,6 @@ public class WindowUpdateFrame extends Frame @Override public String toString() { - return String.format("%s{delta=%d}", super.toString(), windowDelta); + return String.format("%s,delta=%d", super.toString(), windowDelta); } } From 68a3ca8e31e703857b03431498e065156d786813 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 13 Aug 2014 12:00:32 +1000 Subject: [PATCH 232/269] improved debug logging of settings --- .../jetty/http/BadMessageException.java | 3 +- .../org/eclipse/jetty/http2/HTTP2Session.java | 76 +++++++++++-------- .../jetty/http2/frames/SettingsFrame.java | 3 +- .../eclipse/jetty/http2/parser/Parser.java | 24 ++++-- .../http2/parser/SettingsBodyParser.java | 7 ++ .../jetty/http2/hpack/HpackContext.java | 4 +- .../test/resources/jetty-logging.properties | 2 +- .../test/resources/jetty-logging.properties | 2 +- 8 files changed, 80 insertions(+), 41 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java index 014adc89d30..d226d36e9ce 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java @@ -41,13 +41,14 @@ public class BadMessageException extends RuntimeException public BadMessageException(int code, String reason) { + super(code+": "+reason); _code=code; _reason=reason; } public BadMessageException(int code, String reason, Throwable cause) { - super(cause); + super(code+": "+reason, cause); _code=code; _reason=reason; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index a217dd9f89c..6390677677c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -194,43 +194,57 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public boolean onSettings(SettingsFrame frame) { - if (LOG.isDebugEnabled()) - LOG.debug("Received {}", frame); - if (frame.isReply()) return false; - Map<Integer, Integer> settings = frame.getSettings(); - if (settings.containsKey(SettingsFrame.HEADER_TABLE_SIZE)) + // Iterate over all settings + for (Map.Entry<Integer, Integer> entry : frame.getSettings().entrySet()) { - int headerTableSize = settings.get(SettingsFrame.HEADER_TABLE_SIZE); - if (LOG.isDebugEnabled()) - LOG.debug("Updated HPACK header table size to {}", headerTableSize); - generator.setHeaderTableSize(headerTableSize); - } - if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) - { - maxLocalStreams = settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS); - if (LOG.isDebugEnabled()) - LOG.debug("Updated max local concurrent streams to {}", maxLocalStreams); - } - if (settings.containsKey(SettingsFrame.INITIAL_WINDOW_SIZE)) - { - int initialWindow = settings.get(SettingsFrame.INITIAL_WINDOW_SIZE); - flowControl.updateInitialStreamWindow(this, initialWindow); - } - if (settings.containsKey(SettingsFrame.MAX_FRAME_SIZE)) - { - int maxFrameSize = settings.get(SettingsFrame.MAX_FRAME_SIZE); - // SPEC: check the max frame size is sane. - if (maxFrameSize < Frame.DEFAULT_MAX_LENGTH || maxFrameSize > Frame.MAX_MAX_LENGTH) + int value=entry.getValue(); + switch (entry.getKey()) { - onConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_settings_max_frame_size"); - return false; + case SettingsFrame.HEADER_TABLE_SIZE: + if (LOG.isDebugEnabled()) + LOG.debug("Update HPACK header table size to {}", value); + generator.setHeaderTableSize(value); + break; + + case SettingsFrame.ENABLE_PUSH: + break; + + case SettingsFrame.MAX_CONCURRENT_STREAMS: + maxLocalStreams = value; + if (LOG.isDebugEnabled()) + LOG.debug("Update max local concurrent streams to {}", maxLocalStreams); + break; + + case SettingsFrame.INITIAL_WINDOW_SIZE: + if (LOG.isDebugEnabled()) + LOG.debug("Update initial window size to {}", value); + flowControl.updateInitialStreamWindow(this, value); + break; + + case SettingsFrame.MAX_FRAME_SIZE: + if (LOG.isDebugEnabled()) + LOG.debug("Update max frame size to {}", value); + // SPEC: check the max frame size is sane. + if (value < Frame.DEFAULT_MAX_LENGTH || value > Frame.MAX_MAX_LENGTH) + { + onConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_settings_max_frame_size"); + return false; + } + generator.setMaxFrameSize(value); + + break; + + case SettingsFrame.MAX_HEADER_LIST_SIZE: + // TODO implement + LOG.warn("NOT IMPLEMENTED max header list size to {}", value); + break; + + default: + LOG.debug("Unknown setting {}:{}",entry.getKey(),value); } - if (LOG.isDebugEnabled()) - LOG.debug("Updated max frame size to {}", maxFrameSize); - generator.setMaxFrameSize(maxFrameSize); } notifySettings(this, frame); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java index 9909d962988..d782305baca 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -27,7 +27,8 @@ public class SettingsFrame extends Frame public static final int MAX_CONCURRENT_STREAMS = 3; public static final int INITIAL_WINDOW_SIZE = 4; public static final int MAX_FRAME_SIZE = 5; - + public static final int MAX_HEADER_LIST_SIZE = 6; + private final Map<Integer, Integer> settings; private final boolean reply; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index ac4dfaa7161..0a17081007f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -33,6 +33,7 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.hpack.HpackDecoder; import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -76,8 +77,11 @@ public class Parser try { if (LOG.isDebugEnabled()) - LOG.debug("Parsing {}", buffer); - + { + int l=Math.min(buffer.remaining(),16); + LOG.debug("Parsing "+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l)+(l<buffer.remaining()?"...":"")); + } + while (true) { switch (state) @@ -93,7 +97,17 @@ public class Parser { int type = headerParser.getFrameType(); if (LOG.isDebugEnabled()) - LOG.debug("Parsing {} frame", FrameType.from(type)); + { + int fl=headerParser.getLength(); + int l=Math.min(16,Math.min(buffer.remaining(),fl)); + + LOG.debug(String.format("Parsing %s frame %s%s%s", + FrameType.from(type), + " ".substring(0,11-FrameType.from(type).toString().length()), + TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l), + l<fl?"...":"")); + } + if (type < 0 || type >= bodyParsers.length) { notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "unknown_frame_type_" + type); @@ -124,13 +138,13 @@ public class Parser // The content will be processed asynchronously, stop parsing; // the asynchronous operation will eventually resume parsing. if (LOG.isDebugEnabled()) - LOG.debug("Parsed {} frame, asynchronous processing", FrameType.from(type)); + LOG.debug("Parsed {} frame, asynchronous processing", FrameType.from(type)); return true; } case COMPLETE: { if (LOG.isDebugEnabled()) - LOG.debug("Parsed {} frame, synchronous processing", FrameType.from(type)); + LOG.debug("Parsed {} frame, synchronous processing", FrameType.from(type)); reset(); break; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index 5b8cfa61a60..0e49aa16449 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -25,9 +25,12 @@ import java.util.Map; import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.Flags; import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class SettingsBodyParser extends BodyParser { + private static final Logger LOG = Log.getLogger(SettingsBodyParser.class); private State state = State.PREPARE; private int cursor; private int length; @@ -116,6 +119,8 @@ public class SettingsBodyParser extends BodyParser if (buffer.remaining() >= 4) { settingValue = buffer.getInt(); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("setting %d=%d",settingId, settingValue)); settings.put(settingId, settingValue); state = State.SETTING_ID; length -= 4; @@ -144,6 +149,8 @@ public class SettingsBodyParser extends BodyParser } if (cursor == 0) { + if (LOG.isDebugEnabled()) + LOG.debug(String.format("setting %d=%d",settingId, settingValue)); settings.put(settingId, settingValue); state = State.SETTING_ID; if (length == 0) diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index d1cf6172e90..d427212d914 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -306,12 +306,14 @@ public class HpackContext if (entry==_nameMap.get(lc)) _nameMap.remove(lc); } + if (LOG.isDebugEnabled()) + LOG.debug(String.format("HdrTbl[%x] entries=%d, size=%d, max=%d",hashCode(),_headerTable.size(),_headerTableSizeInBytes,_maxHeaderTableSizeInBytes)); } @Override public String toString() { - return String.format("HpackContext@%x{%s}",hashCode(),_headerTable); + return String.format("HpackContext@%x{entries=%d,size=%d,max=%d}",hashCode(),_headerTable.size(),_headerTableSizeInBytes,_maxHeaderTableSizeInBytes); } diff --git a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties index e40e8e43ce1..d33a7c32778 100644 --- a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties @@ -1,3 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog org.eclipse.jetty.http2.LEVEL=INFO -org.eclipse.jetty.http2.hpack.LEVEL=INFO +org.eclipse.jetty.http2.hpack.LEVEL=DEBUG diff --git a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties index 3d1e404e15a..c8c72f381ed 100644 --- a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties @@ -1,3 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.http2.LEVEL=INFO +org.eclipse.jetty.http2.LEVEL=DEBUG From f81bb4c000a7558ace0b64110e27fbec16de1624 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 14 Aug 2014 11:21:08 +1000 Subject: [PATCH 233/269] update OSGi for ssl home and base --- .../jetty/osgi/boot/OSGiServerConstants.java | 3 +- .../DefaultJettyAtJettyHomeHelper.java | 15 +- .../src/test/config/etc/jetty-http.xml | 42 +++++ .../src/test/config/etc/jetty-https.xml | 49 ++---- .../src/test/config/etc/jetty-selector.xml | 31 ---- .../src/test/config/etc/jetty-spdy.xml | 163 ++++++------------ .../src/test/config/etc/jetty-ssl.xml | 57 ++++-- .../TestJettyOSGiBootContextAsService.java | 7 +- .../osgi/test/TestJettyOSGiBootCore.java | 9 +- .../osgi/test/TestJettyOSGiBootSpdy.java | 9 +- .../TestJettyOSGiBootWebAppAsService.java | 7 +- .../osgi/test/TestJettyOSGiBootWithJsp.java | 10 +- 12 files changed, 189 insertions(+), 213 deletions(-) create mode 100644 jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml delete mode 100644 jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-selector.xml diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java index b16eff92e29..4e6247dc3af 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java @@ -30,6 +30,7 @@ public class OSGiServerConstants * configuration. */ public static final String JETTY_HOME = "jetty.home"; + public static final String JETTY_BASE = "jetty.base"; /** * System property to point to a bundle that embeds a jetty configuration @@ -54,7 +55,7 @@ public class OSGiServerConstants * Usual system property used as the port for https for a typical jetty * configuration. */ - public static final String JETTY_PORT_SSL = "jetty.port.ssl"; + public static final String JETTY_PORT_SSL = "ssl.port"; //for managed jetty instances, name of the configuration parameters diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java index 8f22f9768dd..32e5bf7223b 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java @@ -154,22 +154,29 @@ public class DefaultJettyAtJettyHomeHelper List<URL> configURLs = jettyHomeDir != null ? getJettyConfigurationURLs(jettyHomeDir) : getJettyConfigurationURLs(jettyHomeBundle, properties); LOG.info("Configuring the default jetty server with {}",configURLs); - LOG.info("JETTY.HOME="+properties.get(OSGiServerConstants.JETTY_HOME)); + String home=properties.get(OSGiServerConstants.JETTY_HOME); + String base=properties.get(OSGiServerConstants.JETTY_BASE); + LOG.info("JETTY.HOME="+home); + LOG.info("JETTY.BASE="+base); ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(JettyBootstrapActivator.class.getClassLoader()); + //ensure jetty.base is set + if (base==null) + base=home; + // these properties usually are the ones passed to this type of // configuration. properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME); Util.setProperty(properties, OSGiServerConstants.JETTY_HOST, System.getProperty(OSGiServerConstants.JETTY_HOST)); Util.setProperty(properties, OSGiServerConstants.JETTY_PORT, System.getProperty(OSGiServerConstants.JETTY_PORT)); Util.setProperty(properties, OSGiServerConstants.JETTY_PORT_SSL, System.getProperty(OSGiServerConstants.JETTY_PORT_SSL)); - + Util.setProperty(properties, OSGiServerConstants.JETTY_HOME, home); + Util.setProperty(properties, OSGiServerConstants.JETTY_BASE, base); Server server = ServerInstanceWrapper.configure(null, configURLs, properties); - //ensure jetty.home is set - server.setAttribute(OSGiServerConstants.JETTY_HOME, properties.get(OSGiServerConstants.JETTY_HOME)); + //Register the default Server instance as an OSGi service. //The JettyServerServiceTracker will notice it and set it up to deploy bundles as wars etc diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml new file mode 100644 index 00000000000..c3f74f3e668 --- /dev/null +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> + +<!-- ============================================================= --> +<!-- Configure the Jetty Server instance with an ID "Server" --> +<!-- by adding a HTTP connector. --> +<!-- This configuration must be used in conjunction with jetty.xml --> +<!-- ============================================================= --> +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <!-- =========================================================== --> + <!-- Add a HTTP Connector. --> + <!-- Configure an o.e.j.server.ServerConnector with a single --> + <!-- HttpConnectionFactory instance using the common httpConfig --> + <!-- instance defined in jetty.xml --> + <!-- --> + <!-- Consult the javadoc of o.e.j.server.ServerConnector and --> + <!-- o.e.j.server.HttpConnectionFactory for all configuration --> + <!-- that may be set here. --> + <!-- =========================================================== --> + <Call name="addConnector"> + <Arg> + <New class="org.eclipse.jetty.server.ServerConnector"> + <Arg name="server"><Ref refid="Server" /></Arg> + <Arg name="factories"> + <Array type="org.eclipse.jetty.server.ConnectionFactory"> + <Item> + <New class="org.eclipse.jetty.server.HttpConnectionFactory"> + <Arg name="config"><Ref refid="httpConfig" /></Arg> + </New> + </Item> + </Array> + </Arg> + <Set name="host"><Property name="jetty.host" /></Set> + <Set name="port"><Property name="jetty.port" default="80" /></Set> + <Set name="idleTimeout"><Property name="http.timeout" default="30000"/></Set> + <Set name="soLingerTime"><Property name="http.soLingerTime" default="-1"/></Set> + </New> + </Arg> + </Call> + +</Configure> diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml index a6bef16ff1e..f27cec070bd 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml @@ -6,42 +6,23 @@ <!-- This configuration must be used in conjunction with jetty.xml --> <!-- and jetty-ssl.xml. --> <!-- ============================================================= --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> +<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> - <!-- =========================================================== --> - <!-- Add a HTTPS Connector. --> - <!-- Configure an o.e.j.server.ServerConnector with connection --> - <!-- factories for TLS (aka SSL) and HTTP to provide HTTPS. --> - <!-- All accepted TLS connections are wired to a HTTP connection.--> - <!-- --> - <!-- Consult the javadoc of o.e.j.server.ServerConnector, --> - <!-- o.e.j.server.SslConnectionFactory and --> - <!-- o.e.j.server.HttpConnectionFactory for all configuration --> - <!-- that may be set here. --> - <!-- =========================================================== --> - <Call id="httpsConnector" name="addConnector"> + <Call name="addIfAbsentConnectionFactory"> <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"><Ref refid="Server" /></Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - <Item> - <New class="org.eclipse.jetty.server.SslConnectionFactory"> - <Arg name="next">http/1.1</Arg> - <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg> - </New> - </Item> - <Item> - <New class="org.eclipse.jetty.server.HttpConnectionFactory"> - <Arg name="config"><Ref refid="sslHttpConfig"/></Arg> - </New> - </Item> - </Array> - </Arg> - <Set name="host"><Property name="jetty.host" /></Set> - <Set name="port"><Property name="jetty.https.port" default="8443" /></Set> - <Set name="idleTimeout">30000</Set> - </New> + <New class="org.eclipse.jetty.server.SslConnectionFactory"> + <Arg name="next">http/1.1</Arg> + <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg> + </New> </Arg> </Call> + + <Call name="addConnectionFactory"> + <Arg> + <New class="org.eclipse.jetty.server.HttpConnectionFactory"> + <Arg name="config"><Ref refid="sslHttpConfig" /></Arg> + </New> + </Arg> + </Call> + </Configure> diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-selector.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-selector.xml deleted file mode 100644 index 67cd87c2a7e..00000000000 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-selector.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - - <!-- =========================================================== --> - <!-- Add connector --> - <!-- =========================================================== --> - - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg><Ref refid="Server" /></Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - <Item> - <New class="org.eclipse.jetty.server.HttpConnectionFactory"> - <Arg name="config"><Ref refid="httpConfig" /></Arg> - </New> - </Item> - </Array> - </Arg> - <Set name="host"><Property name="jetty.host" /></Set> - <Set name="port"><Property name="jetty.port" default="8080"/></Set> - <Set name="idleTimeout">300000</Set> - </New> - </Arg> - </Call> - -</Configure> diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml index 2bc1fe3cecb..fcb9ce34734 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml @@ -1,115 +1,60 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> +<!-- ============================================================= --> +<!-- Configure a SPDY on the ssl connector. --> +<!-- ============================================================= --> +<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> + + <!-- =========================================================== --> + <!-- Create a push strategy which can be used by reference by --> + <!-- individual connection factories below. --> + <!-- --> + <!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy --> + <!-- for all configuration that may be set here. --> + <!-- =========================================================== --> + <New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy"> + <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the + user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" --> + <!-- + <Set name="UserAgentBlacklist"> + <Array type="String"> + <Item>.*(?i)firefox/14.*</Item> + <Item>.*(?i)firefox/15.*</Item> + <Item>.*(?i)firefox/16.*</Item> + </Array> + </Set> + --> - <!-- =========================================================== --> - <!-- Add HTTP Customizer for Secure request --> - <!-- =========================================================== --> - <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration"> - <Set name="secureScheme">https</Set> - <Set name="securePort"> - <SystemProperty name="jetty.spdy.port" default="8443"/> - </Set> - <Set name="outputBufferSize">32768</Set> - <Set name="requestHeaderSize">8192</Set> - <Set name="responseHeaderSize">8192</Set> - <Call name="addCustomizer"> - <Arg> - <New class="org.eclipse.jetty.server.SecureRequestCustomizer"/> - </Arg> - </Call> - </New> - - - <!-- =========================================================== --> - <!-- Setup a SSL Context factory --> - <!-- =========================================================== --> - <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> - <Set name="KeyStorePath"><Property name="jetty.home" default="."/>/etc/keystore - </Set> - <Set name="KeyStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - <Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - <Set name="TrustStorePath"><Property name="jetty.home" default="."/>/etc/keystore - </Set> - <Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - </New> - - <!-- =========================================================== --> - <!-- Set connectors --> - <!-- =========================================================== --> - <Call id="sslConnector" name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ServerConnector"> - <Arg name="server"> - <Ref refid="Server"/> - </Arg> - <Arg name="factories"> - <Array type="org.eclipse.jetty.server.ConnectionFactory"> - <Item> - <New class="org.eclipse.jetty.server.SslConnectionFactory"> - <Arg name="next">alpn</Arg> - <Arg name="sslContextFactory"> - <Ref refid="sslContextFactory"/> - </Arg> - </New> - </Item> - - <Item> - <New class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory"> - <Arg name="protocols"> - <Array type="String"> - <Item>spdy/3</Item> - <Item>spdy/2</Item> - <Item>http/1.1</Item> - </Array> - </Arg> - <Set name="defaultProtocol">http/1.1</Set> - </New> - </Item> - - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">3</Arg> - <Arg name="config"> - <Ref refid="httpConfig"/> - </Arg> - <!-- Set the initial window size for this SPDY connector. --> - <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> - <Set name="initialWindowSize">65536</Set> - </New> - </Item> - - <Item> - <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> - <Arg name="version" type="int">2</Arg> - <Arg name="config"> - <Ref refid="httpConfig"/> - </Arg> - <!-- Set the initial window size for this SPDY connector. --> - <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> - <Set name="initialWindowSize">65536</Set> - </New> - </Item> - - <Item> - <New class="org.eclipse.jetty.server.HttpConnectionFactory"> - <Arg name="config"> - <Ref refid="httpConfig"/> - </Arg> - </New> - </Item> - </Array> - </Arg> - <Set name="host"> - <Property name="jetty.host"/> - </Set> - <Set name="port"> - <SystemProperty name="jetty.spdy.port" default="8443"/> - </Set> - <Set name="idleTimeout">30000</Set> - </New> - </Arg> - </Call> + <!-- Uncomment to override default file extensions to push --> + <!-- + <Set name="PushRegexps"> + <Array type="String"> + <Item>.*\.css</Item> + <Item>.*\.js</Item> + <Item>.*\.png</Item> + <Item>.*\.jpg</Item> + <Item>.*\.gif</Item> + </Array> + </Set> + --> + <Set name="referrerPushPeriod">5000</Set> + <Set name="maxAssociatedResources">32</Set> + </New> + <!-- SPDY/3 Connection factory --> + <Call name="addConnectionFactory"> + <Arg> + <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory"> + <Arg name="version" type="int">3</Arg> + <Arg name="config"><Ref refid="sslHttpConfig"/></Arg> + <!-- Set the initial window size for this SPDY connector. --> + <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE --> + <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set> + <!-- Uncomment to enable ReferrerPushStrategy --> + <!--<Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg>--> + </New> + </Arg> + </Call> + </Configure> diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml index b4c3551aadc..1014c8507a0 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml @@ -2,19 +2,45 @@ <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <!-- ============================================================= --> -<!-- Configure a TLS (SSL) Context Factory --> -<!-- This configuration must be used in conjunction with jetty.xml --> -<!-- and either jetty-https.xml or jetty-spdy.xml (but not both) --> +<!-- Base SSL configuration --> +<!-- This configuration needs to be used together with 1 or more --> +<!-- of jetty-https.xml, jetty-spdy.xml and/or jetty-http2.xml --> <!-- ============================================================= --> -<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> - <Set name="KeyStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.keystore" default="etc/keystore"/></Set> - <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> - <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set> - <Set name="TrustStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.truststore" default="etc/keystore"/></Set> - <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> - <Set name="EndpointIdentificationAlgorithm"></Set> - <Set name="ExcludeCipherSuites"> - <Array type="String"> +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <!-- =========================================================== --> + <!-- Add a SSL Connector with no protocol factories --> + <!-- =========================================================== --> + <Call name="addConnector"> + <Arg> + <New id="sslConnector" class="org.eclipse.jetty.server.ServerConnector"> + <Arg name="server"><Ref refid="Server" /></Arg> + <Arg name="factories"> + <Array type="org.eclipse.jetty.server.ConnectionFactory"> + </Array> + </Arg> + <Set name="host"><Property name="jetty.host" /></Set> + <Set name="port"><Property name="ssl.port" default="443" /></Set> + <Set name="idleTimeout"><Property name="ssl.timeout" default="30000"/></Set> + <Set name="soLingerTime"><Property name="ssl.soLingerTime" default="-1"/></Set> + </New> + </Arg> + </Call> + + <!-- ============================================================= --> + <!-- Create a TLS (SSL) Context Factory for later reuse --> + <!-- ============================================================= --> + <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> + <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.keystore" default="etc/keystore"/></Set> + <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> + <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set> + <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.truststore" default="etc/keystore"/></Set> + <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> + <Set name="EndpointIdentificationAlgorithm"></Set> + <Set name="NeedClientAuth"><Property name="jetty.ssl.needClientAuth" default="false"/></Set> + <Set name="WantClientAuth"><Property name="jetty.ssl.wantClientAuth" default="false"/></Set> + <Set name="ExcludeCipherSuites"> + <Array type="String"> <Item>SSL_RSA_WITH_DES_CBC_SHA</Item> <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item> <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item> @@ -22,9 +48,10 @@ <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item> <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item> <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item> - </Array> - </Set> - + </Array> + </Set> + </New> + <!-- =========================================================== --> <!-- Create a TLS specific HttpConfiguration based on the --> <!-- common HttpConfiguration defined in jetty.xml --> diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java index 0dfc1bb0e18..07eff6afd7b 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java @@ -70,7 +70,7 @@ public class TestJettyOSGiBootContextAsService { ArrayList<Option> options = new ArrayList<Option>(); options.add(CoreOptions.junitBundles()); - options.addAll(configureJettyHomeAndPort("jetty-selector.xml")); + options.addAll(configureJettyHomeAndPort("jetty-http.xml")); options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*")); options.addAll(TestJettyOSGiBootCore.coreJettyDependencies()); @@ -99,7 +99,8 @@ public class TestJettyOSGiBootContextAsService + "/jetty-deployer.xml;" + etc + "/jetty-testrealm.xml")); - options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT))); + options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT))); + options.add(systemProperty("ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT))); options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath())); return options; } @@ -122,7 +123,7 @@ public class TestJettyOSGiBootContextAsService try { client.start(); - ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT + "/acme/index.html"); + ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/acme/index.html"); assertEquals(HttpStatus.OK_200, response.getStatus()); String content = new String(response.getContent()); diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootCore.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootCore.java index 2565c5be952..c927fb3aec9 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootCore.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootCore.java @@ -47,7 +47,9 @@ import org.osgi.framework.BundleContext; public class TestJettyOSGiBootCore { private static final String LOG_LEVEL = "WARN"; - public static int DEFAULT_JETTY_HTTP_PORT = 9876; + + public static final int DEFAULT_HTTP_PORT = 9876; + public static final int DEFAULT_SSL_PORT = 9877; @Inject private BundleContext bundleContext; @@ -71,7 +73,8 @@ public class TestJettyOSGiBootCore { List<Option> res = new ArrayList<Option>(); // get the jetty home config from the osgi boot bundle. - res.add(CoreOptions.systemProperty("jetty.port").value(String.valueOf(DEFAULT_JETTY_HTTP_PORT))); + res.add(CoreOptions.systemProperty("jetty.port").value(String.valueOf(DEFAULT_HTTP_PORT))); + res.add(CoreOptions.systemProperty("ssl.port").value(String.valueOf(DEFAULT_SSL_PORT))); res.add(CoreOptions.systemProperty("jetty.home.bundle").value("org.eclipse.jetty.osgi.boot")); res.addAll(coreJettyDependencies()); return res; @@ -147,6 +150,6 @@ public class TestJettyOSGiBootCore @Test public void testHttpService() throws Exception { - TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", DEFAULT_JETTY_HTTP_PORT); + TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", DEFAULT_HTTP_PORT); } } diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java index 0cb66a53f25..5bbb5e79ab2 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java @@ -22,7 +22,6 @@ import static org.ops4j.pax.exam.CoreOptions.mavenBundle; import static org.ops4j.pax.exam.CoreOptions.systemProperty; import static org.ops4j.pax.exam.CoreOptions.options; - import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -48,10 +47,7 @@ import org.osgi.framework.BundleContext; public class TestJettyOSGiBootSpdy { private static final String LOG_LEVEL = "WARN"; - - private static final String JETTY_SPDY_PORT = "jetty.spdy.port"; - private static final int DEFAULT_JETTY_SPDY_PORT = 9877; @Inject private BundleContext bundleContext; @@ -74,7 +70,8 @@ public class TestJettyOSGiBootSpdy public static List<Option> spdyJettyDependencies() { List<Option> res = new ArrayList<Option>(); - res.add(CoreOptions.systemProperty(JETTY_SPDY_PORT).value(String.valueOf(DEFAULT_JETTY_SPDY_PORT))); + res.add(CoreOptions.systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT))); + res.add(CoreOptions.systemProperty("ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT))); String alpnBoot = System.getProperty("mortbay-alpn-boot"); if (alpnBoot == null) { throw new IllegalStateException("Define path to alpn boot jar as system property -Dmortbay-alpn-boot"); } @@ -114,7 +111,7 @@ public class TestJettyOSGiBootSpdy @Test public void testSpdyOnHttpService() throws Exception { - TestOSGiUtil.testHttpServiceGreetings(bundleContext, "https", DEFAULT_JETTY_SPDY_PORT); + TestOSGiUtil.testHttpServiceGreetings(bundleContext, "https", TestJettyOSGiBootCore.DEFAULT_SSL_PORT); } } diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWebAppAsService.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWebAppAsService.java index cf2e30fab1d..1ceb5f4f2fe 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWebAppAsService.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWebAppAsService.java @@ -72,7 +72,7 @@ public class TestJettyOSGiBootWebAppAsService { ArrayList<Option> options = new ArrayList<Option>(); options.add(CoreOptions.junitBundles()); - options.addAll(configureJettyHomeAndPort("jetty-selector.xml")); + options.addAll(configureJettyHomeAndPort("jetty-http.xml")); options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*")); options.add(CoreOptions.systemPackages("com.sun.org.apache.xalan.internal.res","com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xpath.internal", @@ -102,7 +102,8 @@ public class TestJettyOSGiBootWebAppAsService + "/jetty-deployer.xml;" + etc + "/jetty-testrealm.xml")); - options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT))); + options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT))); + options.add(systemProperty("ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT))); options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath())); return options; } @@ -144,7 +145,7 @@ public class TestJettyOSGiBootWebAppAsService { client.start(); - ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT + "/acme/index.html"); + ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/acme/index.html"); assertEquals(HttpStatus.OK_200, response.getStatus()); String content = new String(response.getContent()); diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java index b2a9be58876..90ff7f194bb 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java @@ -63,7 +63,7 @@ public class TestJettyOSGiBootWithJsp ArrayList<Option> options = new ArrayList<Option>(); options.add(CoreOptions.junitBundles()); - options.addAll(configureJettyHomeAndPort("jetty-selector.xml")); + options.addAll(configureJettyHomeAndPort("jetty-http.xml")); options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*", "javax.activation.*")); options.add(CoreOptions.systemPackages("com.sun.org.apache.xalan.internal.res","com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xpath.internal", @@ -98,8 +98,10 @@ public class TestJettyOSGiBootWithJsp + "/jetty-testrealm.xml"; options.add(systemProperty(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS).value(xmlConfigs)); - options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT))); + options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT))); + options.add(systemProperty("ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT))); options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath())); + options.add(systemProperty("jetty.base").value(etcFolder.getParentFile().getAbsolutePath())); return options; } @@ -135,7 +137,7 @@ public class TestJettyOSGiBootWithJsp @Test public void testHttpService() throws Exception { - TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT); + TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", TestJettyOSGiBootCore.DEFAULT_HTTP_PORT); } @@ -146,7 +148,7 @@ public class TestJettyOSGiBootWithJsp try { client.start(); - ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT + "/jsp/dump.jsp"); + ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/jsp/dump.jsp"); assertEquals(HttpStatus.OK_200, response.getStatus()); String content = new String(response.getContent()); From a14d84338204fffaf0da7c2681271d6262a85100 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 14 Aug 2014 15:18:28 +1000 Subject: [PATCH 234/269] ignored osgi-spdy tests --- jetty-deploy/pom.xml | 2 +- jetty-http2/pom.xml | 2 +- jetty-nosql/pom.xml | 2 +- .../DefaultJettyAtJettyHomeHelper.java | 11 ++- .../serverfactory/ServerInstanceWrapper.java | 78 +++++++++---------- .../src/test/config/etc/jetty-spdy.xml | 30 +------ .../osgi/test/TestJettyOSGiBootSpdy.java | 15 ++-- .../osgi/test/TestJettyOSGiBootWithJsp.java | 32 ++++---- jetty-server/pom.xml | 2 +- jetty-servlet/pom.xml | 2 +- jetty-spdy/pom.xml | 2 +- jetty-spdy/spdy-client/pom.xml | 4 +- jetty-spdy/spdy-http-client-transport/pom.xml | 2 +- jetty-spdy/spdy-http-common/pom.xml | 2 +- jetty-spdy/spdy-http-server/pom.xml | 4 +- jetty-spdy/spdy-server/pom.xml | 2 +- jetty-websocket/pom.xml | 2 +- .../eclipse/jetty/xml/XmlConfiguration.java | 2 +- tests/test-webapps/test-jetty-webapp/pom.xml | 2 +- 19 files changed, 87 insertions(+), 111 deletions(-) diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index 9a843df37e0..fbdff7dbbd9 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -25,7 +25,7 @@ </goals> <configuration> <instructions> - <Import-Package>org.eclipse.jetty.jmx.*;version="9.1";resolution:=optional,*</Import-Package> + <Import-Package>org.eclipse.jetty.jmx.*;resolution:=optional,*</Import-Package> <_nouses>true</_nouses> </instructions> </configuration> diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index fb706303761..0e6574e1a7d 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -32,7 +32,7 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.http2.*;version="9.1"</Export-Package> + <Export-Package>org.eclipse.jetty.http2.*"</Export-Package> <Import-Package>org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <_nouses>true</_nouses> </instructions> diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index f283899a5ba..92c7d77fd09 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -36,7 +36,7 @@ <artifactId>maven-bundle-plugin</artifactId> <configuration> <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.server.session.jmx;version="9.1";resolution:=optional,,org.eclipse.jetty.*;version="9.1",*</Import-Package> + <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.server.session.jmx;resolution:=optional,org.eclipse.jetty.*,*</Import-Package> </instructions> </configuration> <extensions>true</extensions> diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java index 32e5bf7223b..1347c65563a 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java @@ -156,6 +156,8 @@ public class DefaultJettyAtJettyHomeHelper LOG.info("Configuring the default jetty server with {}",configURLs); String home=properties.get(OSGiServerConstants.JETTY_HOME); String base=properties.get(OSGiServerConstants.JETTY_BASE); + if (base==null) + base=home; LOG.info("JETTY.HOME="+home); LOG.info("JETTY.BASE="+base); ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); @@ -163,10 +165,6 @@ public class DefaultJettyAtJettyHomeHelper { Thread.currentThread().setContextClassLoader(JettyBootstrapActivator.class.getClassLoader()); - //ensure jetty.base is set - if (base==null) - base=home; - // these properties usually are the ones passed to this type of // configuration. properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME); @@ -184,6 +182,11 @@ public class DefaultJettyAtJettyHomeHelper LOG.info("Default jetty server configured"); return server; } + catch (Exception e) + { + LOG.warn(e); + throw e; + } finally { Thread.currentThread().setContextClassLoader(contextCl); diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java index c4bc8c529c5..dc94d6d2f54 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java @@ -147,47 +147,42 @@ public class ServerInstanceWrapper for (URL jettyConfiguration : jettyConfigurations) { - InputStream is = null; - try - { - // Execute a Jetty configuration file - Resource r = Resource.newResource(jettyConfiguration); - if (!r.exists()) - { - LOG.warn("File does not exist "+r); - throw new IllegalStateException("No such jetty server config file: "+r); - } - is = r.getInputStream(); - XmlConfiguration config = new XmlConfiguration(is); - config.getIdMap().putAll(id_map); - config.getProperties().putAll(properties); - - // #334062 compute the URL of the folder that contains the - // conf file and set it as a property so we can compute relative paths - // from it. - String urlPath = jettyConfiguration.toString(); - int lastSlash = urlPath.lastIndexOf('/'); - if (lastSlash > 4) - { - urlPath = urlPath.substring(0, lastSlash); - config.getProperties().put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath); - } - - Object o = config.configure(); - if (server == null) - server = (Server)o; - - id_map = config.getIdMap(); - } - catch (SAXParseException saxparse) - { - LOG.warn("Unable to configure the jetty/etc file " + jettyConfiguration, saxparse); - throw saxparse; - } - finally - { - IO.close(is); - } + try(Resource r = Resource.newResource(jettyConfiguration)) + { + // Execute a Jetty configuration file + if (!r.exists()) + { + LOG.warn("File does not exist "+r); + throw new IllegalStateException("No such jetty server config file: "+r); + } + + XmlConfiguration config = new XmlConfiguration(r.getURL()); + + config.getIdMap().putAll(id_map); + config.getProperties().putAll(properties); + + // #334062 compute the URL of the folder that contains the + // conf file and set it as a property so we can compute relative paths + // from it. + String urlPath = jettyConfiguration.toString(); + int lastSlash = urlPath.lastIndexOf('/'); + if (lastSlash > 4) + { + urlPath = urlPath.substring(0, lastSlash); + config.getProperties().put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath); + } + + Object o = config.configure(); + if (server == null) + server = (Server)o; + + id_map = config.getIdMap(); + } + catch (Exception e) + { + LOG.warn("Configuration error in " + jettyConfiguration); + throw e; + } } return server; @@ -250,7 +245,6 @@ public class ServerInstanceWrapper return _ctxtCollection; } - /* ------------------------------------------------------------ */ public void start(Server server, Dictionary props) throws Exception { diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml index fcb9ce34734..a0e9d1a11b8 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml @@ -13,35 +13,7 @@ <!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy --> <!-- for all configuration that may be set here. --> <!-- =========================================================== --> - <New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy"> - <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the - user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" --> - <!-- - <Set name="UserAgentBlacklist"> - <Array type="String"> - <Item>.*(?i)firefox/14.*</Item> - <Item>.*(?i)firefox/15.*</Item> - <Item>.*(?i)firefox/16.*</Item> - </Array> - </Set> - --> - - <!-- Uncomment to override default file extensions to push --> - <!-- - <Set name="PushRegexps"> - <Array type="String"> - <Item>.*\.css</Item> - <Item>.*\.js</Item> - <Item>.*\.png</Item> - <Item>.*\.jpg</Item> - <Item>.*\.gif</Item> - </Array> - </Set> - --> - <Set name="referrerPushPeriod">5000</Set> - <Set name="maxAssociatedResources">32</Set> - </New> - + <!-- SPDY/3 Connection factory --> <Call name="addConnectionFactory"> <Arg> diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java index 5bbb5e79ab2..df05da81575 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java @@ -44,6 +44,7 @@ import org.osgi.framework.BundleContext; * SPDY setup. */ @RunWith(PaxExam.class) +@Ignore public class TestJettyOSGiBootSpdy { private static final String LOG_LEVEL = "WARN"; @@ -56,14 +57,18 @@ public class TestJettyOSGiBootSpdy public Option[] config() { ArrayList<Option> options = new ArrayList<Option>(); - options.addAll(TestJettyOSGiBootWithJsp.configureJettyHomeAndPort("jetty-spdy.xml")); + options.addAll(TestJettyOSGiBootWithJsp.configureJettyHomeAndPort(true,"jetty-spdy.xml")); options.addAll(TestJettyOSGiBootCore.coreJettyDependencies()); options.addAll(spdyJettyDependencies()); options.add(CoreOptions.junitBundles()); options.addAll(TestJettyOSGiBootCore.httpServiceJetty()); options.addAll(Arrays.asList(options(systemProperty("pax.exam.logging").value("none")))); - options.addAll(Arrays.asList(options(systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(LOG_LEVEL)))); - options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.LEVEL").value(LOG_LEVEL)))); + options.addAll(Arrays.asList(options(systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG")))); + options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.LEVEL").value("INFO")))); + options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.osgi.LEVEL").value("DEBUG")))); + options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.util.component.LEVEL").value("DEBUG")))); + options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.server.LEVEL").value("DEBUG")))); + options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.xml.LEVEL").value("INFO")))); return options.toArray(new Option[options.size()]); } @@ -78,14 +83,13 @@ public class TestJettyOSGiBootSpdy File checkALPNBoot = new File(alpnBoot); if (!checkALPNBoot.exists()) { throw new IllegalStateException("Unable to find the alpn boot jar here: " + alpnBoot); } - res.add(CoreOptions.vmOptions("-Xbootclasspath/p:" + alpnBoot)); res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-alpn").versionAsInProject().noStart()); res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-alpn-server").versionAsInProject().start()); - res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-client").versionAsInProject().noStart()); res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-core").versionAsInProject().noStart()); + res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-client").versionAsInProject().start()); res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-server").versionAsInProject().noStart()); res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-http-common").versionAsInProject().noStart()); res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-http-server").versionAsInProject().noStart()); @@ -111,6 +115,7 @@ public class TestJettyOSGiBootSpdy @Test public void testSpdyOnHttpService() throws Exception { + TestOSGiUtil.debugBundles(bundleContext); TestOSGiUtil.testHttpServiceGreetings(bundleContext, "https", TestJettyOSGiBootCore.DEFAULT_SSL_PORT); } diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java index 90ff7f194bb..0032744e4b8 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java @@ -60,10 +60,9 @@ public class TestJettyOSGiBootWithJsp @Configuration public static Option[] configure() { - ArrayList<Option> options = new ArrayList<Option>(); options.add(CoreOptions.junitBundles()); - options.addAll(configureJettyHomeAndPort("jetty-http.xml")); + options.addAll(configureJettyHomeAndPort(false,"jetty-http.xml")); options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*", "javax.activation.*")); options.add(CoreOptions.systemPackages("com.sun.org.apache.xalan.internal.res","com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xpath.internal", @@ -78,23 +77,26 @@ public class TestJettyOSGiBootWithJsp return options.toArray(new Option[options.size()]); } - public static List<Option> configureJettyHomeAndPort(String jettySelectorFileName) + public static List<Option> configureJettyHomeAndPort(boolean ssl,String jettySelectorFileName) { File etcFolder = new File("src/test/config/etc"); String etc = "file://" + etcFolder.getAbsolutePath(); List<Option> options = new ArrayList<Option>(); - String xmlConfigs = etc + "/jetty.xml;" - + etc - + "/" - + jettySelectorFileName - + ";" - + etc - + "/jetty-ssl.xml;" - + etc - + "/jetty-https.xml;" - + etc - + "/jetty-deployer.xml;" - + etc + String xmlConfigs = etc + "/jetty.xml"; + if (ssl) + xmlConfigs += ";" + + etc + + "/jetty-ssl.xml;" + + etc + + "/jetty-https.xml;"; + xmlConfigs+= ";" + + etc + + "/" + + jettySelectorFileName + + ";" + + etc + + "/jetty-deployer.xml;" + + etc + "/jetty-testrealm.xml"; options.add(systemProperty(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS).value(xmlConfigs)); diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index 33d50c6ef5f..c01cb9a7668 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -26,7 +26,7 @@ </goals> <configuration> <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.jmx.*;version="9.1";resolution:=optional,*</Import-Package> + <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.jmx.*;resolution:=optional,*</Import-Package> <_nouses>true</_nouses> </instructions> </configuration> diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index f5a3b528411..1bcc0866838 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -26,7 +26,7 @@ </goals> <configuration> <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.jmx.*;version="9.1";resolution:=optional,*</Import-Package> + <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.jmx.*;resolution:=optional,*</Import-Package> <_nouses>true</_nouses> </instructions> </configuration> diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index 7e1bdf0db8b..a4890554183 100644 --- a/jetty-spdy/pom.xml +++ b/jetty-spdy/pom.xml @@ -55,7 +55,7 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.*;version="9.1"</Export-Package> + <Export-Package>org.eclipse.jetty.spdy.*</Export-Package> <Import-Package>org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <_nouses>true</_nouses> </instructions> diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml index 3fe70e3c710..4784dd7d271 100644 --- a/jetty-spdy/spdy-client/pom.xml +++ b/jetty-spdy/spdy-client/pom.xml @@ -28,8 +28,8 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.client;version="9.1"</Export-Package> - <Import-Package>!org.eclipse.jetty.npn,!org.eclipse.jetty.alpn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> + <Export-Package>org.eclipse.jetty.spdy.client</Export-Package> + <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.npn.client;resolution:=optional,!org.eclipse.jetty.alpn,org.eclipse.jetty.alpn.client;resolution:=optional,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> </instructions> </configuration> </execution> diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml index 2562ac25871..028b99817ea 100644 --- a/jetty-spdy/spdy-http-client-transport/pom.xml +++ b/jetty-spdy/spdy-http-client-transport/pom.xml @@ -27,7 +27,7 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.client.http;version="9.1"</Export-Package> + <Export-Package>org.eclipse.jetty.spdy.client.http</Export-Package> <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> </instructions> </configuration> diff --git a/jetty-spdy/spdy-http-common/pom.xml b/jetty-spdy/spdy-http-common/pom.xml index d9b607888b3..0857515bd3b 100644 --- a/jetty-spdy/spdy-http-common/pom.xml +++ b/jetty-spdy/spdy-http-common/pom.xml @@ -27,7 +27,7 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.http;version="9.1"</Export-Package> + <Export-Package>org.eclipse.jetty.spdy.http</Export-Package> <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> </instructions> </configuration> diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml index f5a6373fa03..ffe9f134fe8 100644 --- a/jetty-spdy/spdy-http-server/pom.xml +++ b/jetty-spdy/spdy-http-server/pom.xml @@ -56,8 +56,8 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.server.http;version="9.1", - org.eclipse.jetty.spdy.server.proxy;version="9.1" + <Export-Package>org.eclipse.jetty.spdy.server.http, + org.eclipse.jetty.spdy.server.proxy;version="9.3" </Export-Package> <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",* </Import-Package> diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index 83e98333509..5f8e53972fc 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -28,7 +28,7 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.server;version="9.1"</Export-Package> + <Export-Package>org.eclipse.jetty.spdy.server</Export-Package> <Import-Package>org.eclipse.jetty.alpn;resolution:=optional,org.eclipse.jetty.alpn.server;resolution:=optional, org.eclipse.jetty.npn;resolution:=optional,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <_nouses>true</_nouses> </instructions> diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 941a7900c41..7a209faeb26 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -43,7 +43,7 @@ </goals> <configuration> <instructions> - <Export-Package>${bundle-symbolic-name}.*;version="9.1"</Export-Package> + <Export-Package>${bundle-symbolic-name}.*</Export-Package> <Import-Package>javax.servlet.*;version="[3.0,4.0)",org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <_nouses>true</_nouses> </instructions> diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index 3b88bdc8935..684216ff17d 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -346,7 +346,7 @@ public class XmlConfiguration } catch (NoSuchMethodException x) { - throw new IllegalStateException("No suitable constructor on " + oClass, x); + throw new IllegalStateException(String.format("No constructor %s(%s,%s) in %s",oClass,arguments,namedArgMap,_url)); } } _configuration.initializeDefaults(obj); diff --git a/tests/test-webapps/test-jetty-webapp/pom.xml b/tests/test-webapps/test-jetty-webapp/pom.xml index e45681105e1..49ee81234c7 100644 --- a/tests/test-webapps/test-jetty-webapp/pom.xml +++ b/tests/test-webapps/test-jetty-webapp/pom.xml @@ -98,7 +98,7 @@ <configuration> <instructions> <Bundle-SymbolicName>org.eclipse.jetty.test-jetty-webapp</Bundle-SymbolicName> - <Import-Package>javax.servlet.jsp.*;version="[2.2.0, 3.0)",javax.servlet.*;version="[2.6,3.2)",org.eclipse.jetty.*;version="9.1",*</Import-Package> + <Import-Package>javax.servlet.jsp.*;version="[2.2.0,3.0)",javax.servlet.*;version="[2.6,3.2)",org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <Export-Package>!com.acme*</Export-Package> <!-- the test webapp is configured via a jetty xml file in order to add the security handler. --> From a2360bd542c28222ee91ee36f383b4a03caef9ba Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Thu, 14 Aug 2014 23:00:21 +0200 Subject: [PATCH 235/269] Fixed creation of HttpURI for push requests. --- .../src/main/java/org/eclipse/jetty/server/Dispatcher.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java index c105b3cfd78..cd19dedd724 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; - import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; @@ -34,7 +33,6 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.Attributes; @@ -230,7 +228,7 @@ public class Dispatcher implements RequestDispatcher else query=query+"&"+_uri.getQuery(); // TODO is this correct semantic? } - HttpURI uri = new HttpURI(request.getProtocol(),request.getServerName(),request.getServerPort(),_uri.getPath(),baseRequest.getHttpURI().getParam(),query,null); + HttpURI uri = new HttpURI(request.getScheme(),request.getServerName(),request.getServerPort(),_uri.getPath(),baseRequest.getHttpURI().getParam(),query,null); MetaData.Request push = new MetaData.Request(HttpMethod.GET.asString(),uri,baseRequest.getHttpVersion(),fields); From 48b1f9f3f1e472588b1f4118e8fda101bfe3a1c8 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Thu, 14 Aug 2014 23:05:35 +0200 Subject: [PATCH 236/269] Implemented HTTP/2 push functionality. A PushCacheFilter contains the logic to associate secondary resources to primary resources. PushCacheFilter calls a Jetty-specific API on the request dispatcher: Dispatcher.push(ServletRequest). This is a technology preview of the push functionality slated for Servlet 4.0. The push() invocation arrives to the transport and it is converted to HTTP/2 specific PUSH_PROMISE, along with the mechanism to simulate the request for the secondary resource. --- jetty-http2/http2-client/pom.xml | 6 + .../http2/client/HTTP2ClientSession.java | 47 ++++++ .../jetty/http2/client/AbstractTest.java | 33 ++-- .../eclipse/jetty/http2/client/PushTest.java | 139 +++++++++++++++++ .../org/eclipse/jetty/http2/HTTP2Session.java | 46 ++++-- .../org/eclipse/jetty/http2/HTTP2Stream.java | 20 ++- .../org/eclipse/jetty/http2/ISession.java | 5 + .../java/org/eclipse/jetty/http2/IStream.java | 2 + .../org/eclipse/jetty/http2/api/Stream.java | 15 +- .../jetty/http2/frames/PushPromiseFrame.java | 6 + .../eclipse/jetty/http2/parser/Parser.java | 12 +- .../server/HTTP2ServerConnectionFactory.java | 37 ++++- .../http2/server/HTTP2ServerSession.java | 36 +++-- .../http2/server/HttpChannelOverHTTP2.java | 30 ++-- .../http2/server/HttpTransportOverHTTP2.java | 49 ++++-- .../jetty/servlets/PushCacheFilter.java | 146 +++++++++--------- 16 files changed, 471 insertions(+), 158 deletions(-) create mode 100644 jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java diff --git a/jetty-http2/http2-client/pom.xml b/jetty-http2/http2-client/pom.xml index 60c4bb96f47..0f5372000de 100644 --- a/jetty-http2/http2-client/pom.xml +++ b/jetty-http2/http2-client/pom.xml @@ -72,6 +72,12 @@ <version>${project.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlets</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>org.eclipse.jetty.http2</groupId> <artifactId>http2-server</artifactId> diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index e7644e7df6d..7a47f81cbca 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -24,6 +24,7 @@ import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.io.EndPoint; @@ -44,6 +45,9 @@ public class HTTP2ClientSession extends HTTP2Session @Override public boolean onHeaders(HeadersFrame frame) { + if (LOG.isDebugEnabled()) + LOG.debug("Received {}", frame); + int streamId = frame.getStreamId(); IStream stream = getStream(streamId); if (stream == null) @@ -76,4 +80,47 @@ public class HTTP2ClientSession extends HTTP2Session LOG.info("Failure while notifying listener " + listener, x); } } + + @Override + public boolean onPushPromise(PushPromiseFrame frame) + { + if (LOG.isDebugEnabled()) + LOG.debug("Received {}", frame); + + int streamId = frame.getStreamId(); + int pushStreamId = frame.getPromisedStreamId(); + IStream stream = getStream(streamId); + if (stream == null) + { + ResetFrame reset = new ResetFrame(pushStreamId, ErrorCodes.STREAM_CLOSED_ERROR); + reset(reset, disconnectOnFailure()); + } + else + { + IStream pushStream = createRemoteStream(pushStreamId); + pushStream.updateClose(true, true); + pushStream.process(frame, Callback.Adapter.INSTANCE); + Stream.Listener listener = notifyPush(stream, pushStream, frame); + pushStream.setListener(listener); + if (pushStream.isClosed()) + removeStream(pushStream, false); + } + return false; + } + + private Stream.Listener notifyPush(IStream stream, IStream pushStream, PushPromiseFrame frame) + { + Stream.Listener listener = stream.getListener(); + if (listener == null) + return null; + try + { + return listener.onPush(pushStream, frame); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + return null; + } + } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java index ab9357ed8f8..fd2fcd9edf8 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.http2.client; import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; - import javax.servlet.http.HttpServlet; import org.eclipse.jetty.http.HostPortHttpField; @@ -45,7 +44,7 @@ import org.junit.After; public class AbstractTest { protected ServerConnector connector; - private String path = "/test"; + protected String servletPath = "/test"; protected HTTP2Client client; private Server server; @@ -53,8 +52,9 @@ public class AbstractTest { prepareServer(new HTTP2ServerConnectionFactory(new HttpConfiguration())); - ServletContextHandler context = new ServletContextHandler(server, "/"); - context.addServlet(new ServletHolder(servlet), path); + ServletContextHandler context = new ServletContextHandler(server, "/", true, false); + context.addServlet(new ServletHolder(servlet), servletPath + "/*"); + customizeContext(context); prepareClient(); @@ -62,6 +62,10 @@ public class AbstractTest client.start(); } + protected void customizeContext(ServletContextHandler context) + { + } + protected void startServer(ServerSessionListener listener) throws Exception { prepareServer(new RawHTTP2ServerConnectionFactory(listener)); @@ -96,18 +100,23 @@ public class AbstractTest return promise.get(5, TimeUnit.SECONDS); } + protected MetaData.Request newRequest(String method, HttpFields fields) + { + return newRequest(method, "", fields); + } + + protected MetaData.Request newRequest(String method, String pathInfo, HttpFields fields) + { + String host = "localhost"; + int port = connector.getLocalPort(); + String authority = host + ":" + port; + return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), servletPath + pathInfo, HttpVersion.HTTP_2, fields); + } + @After public void dispose() throws Exception { client.stop(); server.stop(); } - - protected MetaData.Request newRequest(String method, HttpFields fields) - { - String host = "localhost"; - int port = connector.getLocalPort(); - String authority = host + ":" + port; - return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields); - } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java new file mode 100644 index 00000000000..4f622816d07 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java @@ -0,0 +1,139 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client; + +import java.io.IOException; +import java.util.EnumSet; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.servlet.DispatcherType; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlets.PushCacheFilter; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; +import org.junit.Assert; +import org.junit.Test; + +public class PushTest extends AbstractTest +{ + @Override + protected void customizeContext(ServletContextHandler context) + { + context.addFilter(PushCacheFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); + } + + @Test + public void testPush() throws Exception + { + final String primaryResource = "/primary.html"; + final String secondaryResource = "/secondary.png"; + final byte[] secondaryData = "SECONDARY".getBytes("UTF-8"); + startServer(new HttpServlet() + { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + String requestURI = req.getRequestURI(); + ServletOutputStream output = resp.getOutputStream(); + if (requestURI.endsWith(primaryResource)) + output.print("<html><head></head><body>PRIMARY</body></html>"); + else if (requestURI.endsWith(secondaryResource)) + output.write(secondaryData); + } + }); + + final Session session = newClient(new Session.Listener.Adapter()); + + // Request for the primary and secondary resource to build the cache. + final String primaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource; + HttpFields primaryFields = new HttpFields(); + MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields); + final CountDownLatch secondaryResponseLatch = new CountDownLatch(1); + session.newStream(new HeadersFrame(0, primaryRequest, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + { + // Request for the secondary resource. + HttpFields secondaryFields = new HttpFields(); + secondaryFields.put(HttpHeader.REFERER, primaryURI); + MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields); + session.newStream(new HeadersFrame(0, secondaryRequest, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + secondaryResponseLatch.countDown(); + } + }); + } + } + }); + Assert.assertTrue(secondaryResponseLatch.await(5, TimeUnit.SECONDS)); + + // Request again the primary resource, we should get the secondary resource pushed. + primaryRequest = newRequest("GET", primaryResource, primaryFields); + final CountDownLatch primaryResponseLatch = new CountDownLatch(1); + final CountDownLatch pushLatch = new CountDownLatch(1); + session.newStream(new HeadersFrame(0, primaryRequest, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public Stream.Listener onPush(Stream stream, PushPromiseFrame frame) + { + return new Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + pushLatch.countDown(); + } + }; + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + primaryResponseLatch.countDown(); + } + }); + Assert.assertTrue(pushLatch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS)); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 6390677677c..01e768b741f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -254,13 +254,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return false; } - @Override - public boolean onPushPromise(PushPromiseFrame frame) - { - // TODO - return false; - } - @Override public boolean onPing(PingFrame frame) { @@ -332,7 +325,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener priority = priority == null ? null : new PriorityFrame(streamId, priority.getDependentStreamId(), priority.getWeight(), priority.isExclusive()); frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream()); - final IStream stream = createLocalStream(frame, promise); + final IStream stream = createLocalStream(streamId, promise); if (stream == null) return; stream.updateClose(frame.isEndStream(), true); @@ -345,6 +338,28 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.iterate(); } + @Override + public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame) + { + // Synchronization is necessary to atomically create + // the stream id and enqueue the frame to be sent. + synchronized (this) + { + int streamId = streamIds.getAndAdd(2); + frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData()); + + final IStream pushStream = createLocalStream(streamId, promise); + if (pushStream == null) + return; + pushStream.updateClose(true, false); + + ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream)); + flusher.append(entry); + } + // Iterate outside the synchronized block. + flusher.iterate(); + } + @Override public void settings(SettingsFrame frame, Callback callback) { @@ -414,7 +429,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.iterate(); } - protected IStream createLocalStream(HeadersFrame frame, Promise<Stream> promise) + protected IStream createLocalStream(int streamId, Promise<Stream> promise) { while (true) { @@ -429,8 +444,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener break; } - IStream stream = newStream(frame); - int streamId = stream.getId(); + IStream stream = newStream(streamId); if (streams.putIfAbsent(streamId, stream) == null) { stream.setIdleTimeout(endPoint.getIdleTimeout()); @@ -446,10 +460,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } - protected IStream createRemoteStream(HeadersFrame frame) + protected IStream createRemoteStream(int streamId) { - int streamId = frame.getStreamId(); - // SPEC: exceeding max concurrent streams is treated as stream error. while (true) { @@ -464,7 +476,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener break; } - IStream stream = newStream(frame); + IStream stream = newStream(streamId); // SPEC: duplicate stream is treated as connection error. if (streams.putIfAbsent(streamId, stream) == null) @@ -483,9 +495,9 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } } - protected IStream newStream(HeadersFrame frame) + protected IStream newStream(int streamId) { - return new HTTP2Stream(scheduler, this, frame); + return new HTTP2Stream(scheduler, this, streamId); } protected void removeStream(IStream stream, boolean local) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index bd7668eeb93..f22a93c915f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -28,9 +28,11 @@ import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.io.IdleTimeout; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Scheduler; @@ -52,21 +54,21 @@ public class HTTP2Stream extends IdleTimeout implements IStream private final AtomicInteger sendWindow = new AtomicInteger(); private final AtomicInteger recvWindow = new AtomicInteger(); private final ISession session; - private final HeadersFrame frame; + private final int streamId; private volatile Listener listener; private volatile boolean reset; - public HTTP2Stream(Scheduler scheduler, ISession session, HeadersFrame frame) + public HTTP2Stream(Scheduler scheduler, ISession session, int streamId) { super(scheduler); this.session = session; - this.frame = frame; + this.streamId = streamId; } @Override public int getId() { - return frame.getStreamId(); + return streamId; } @Override @@ -81,6 +83,12 @@ public class HTTP2Stream extends IdleTimeout implements IStream session.control(this, callback, frame, Frame.EMPTY_ARRAY); } + @Override + public void push(PushPromiseFrame frame, Promise<Stream> promise) + { + session.push(this, promise, frame); + } + @Override public void data(DataFrame frame, Callback callback) { @@ -198,6 +206,10 @@ public class HTTP2Stream extends IdleTimeout implements IStream reset = true; return false; } + case PUSH_PROMISE: + { + return false; + } default: { throw new UnsupportedOperationException(); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index d40ba0b1901..024922ce509 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -19,10 +19,13 @@ package org.eclipse.jetty.http2; import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; public interface ISession extends Session { @@ -31,6 +34,8 @@ public interface ISession extends Session public void control(IStream stream, Callback callback, Frame frame, Frame... frames); + public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame); + public void data(IStream stream, Callback callback, DataFrame frame); public int updateSendWindow(int delta); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 0139f12d0fe..c493fae171b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -24,6 +24,8 @@ import org.eclipse.jetty.util.Callback; public interface IStream extends Stream { + public static final String CHANNEL_ATTRIBUTE = IStream.class.getName() + ".channel"; + @Override public ISession getSession(); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index b6af7e71e7f..c5aa7f2bed2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -20,7 +20,9 @@ package org.eclipse.jetty.http2.api; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; public interface Stream { @@ -30,6 +32,8 @@ public interface Stream public void headers(HeadersFrame frame, Callback callback); + public void push(PushPromiseFrame frame, Promise<Stream> promise); + public void data(DataFrame frame, Callback callback); public Object getAttribute(String key); @@ -52,13 +56,12 @@ public interface Stream { public void onHeaders(Stream stream, HeadersFrame frame); + public Listener onPush(Stream stream, PushPromiseFrame frame); + public void onData(Stream stream, DataFrame frame, Callback callback); - // TODO: is this method needed ? public void onFailure(Stream stream, Throwable x); - // TODO: See SPDY's StreamFrameListener - public static class Adapter implements Listener { @Override @@ -66,6 +69,12 @@ public interface Stream { } + @Override + public Listener onPush(Stream stream, PushPromiseFrame frame) + { + return null; + } + @Override public void onData(Stream stream, DataFrame frame, Callback callback) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java index a1c44124957..c4d0b7090db 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java @@ -48,4 +48,10 @@ public class PushPromiseFrame extends Frame { return metaData; } + + @Override + public String toString() + { + return String.format("%s#%d/%d", super.toString(), streamId, promisedStreamId); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 0a17081007f..a716ccc4578 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -97,17 +97,7 @@ public class Parser { int type = headerParser.getFrameType(); if (LOG.isDebugEnabled()) - { - int fl=headerParser.getLength(); - int l=Math.min(16,Math.min(buffer.remaining(),fl)); - - LOG.debug(String.format("Parsing %s frame %s%s%s", - FrameType.from(type), - " ".substring(0,11-FrameType.from(type).toString().length()), - TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l), - l<fl?"...":"")); - } - + LOG.debug("Parsing {} frame", FrameType.from(type)); if (type < 0 || type >= bodyParsers.length) { notifyConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "unknown_frame_type_" + type); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index fb6403c4c21..5c39454ff18 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -21,12 +21,16 @@ package org.eclipse.jetty.http2.server; import java.util.HashMap; import java.util.Map; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; +import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.ByteBufferPool; @@ -41,7 +45,6 @@ import org.eclipse.jetty.util.log.Logger; public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionFactory { private static final Logger LOG = Log.getLogger(HTTP2ServerConnectionFactory.class); - private static final String CHANNEL_ATTRIBUTE = HttpChannelOverHTTP2.class.getName(); private final HttpConfiguration httpConfiguration; @@ -93,14 +96,14 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF if (LOG.isDebugEnabled()) LOG.debug("Processing {} on {}", frame, stream); - HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2((IStream)stream, frame); + MetaData.Request request = (MetaData.Request)frame.getMetaData(); + HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2(connector, httpConfiguration, endPoint, (IStream)stream, request); HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); - // TODO pool HttpChannels per connection - maybe associate with thread? HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input, stream); - stream.setAttribute(CHANNEL_ATTRIBUTE, channel); + stream.setAttribute(IStream.CHANNEL_ATTRIBUTE, channel); - channel.onHeadersFrame(frame); + channel.onRequest(frame); return frame.isEndStream() ? null : this; } @@ -109,6 +112,15 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF public void onHeaders(Stream stream, HeadersFrame frame) { // Servers do not receive responses. + close(stream, "response_headers"); + } + + @Override + public Stream.Listener onPush(Stream stream, PushPromiseFrame frame) + { + // Servers do not receive pushes. + close(stream, "push_promise"); + return null; } @Override @@ -117,7 +129,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF if (LOG.isDebugEnabled()) LOG.debug("Processing {} on {}", frame, stream); - HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(CHANNEL_ATTRIBUTE); + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); channel.requestContent(frame, callback); } @@ -126,5 +138,18 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF { // TODO } + + private void close(Stream stream, String reason) + { + final Session session = stream.getSession(); + session.close(ErrorCodes.PROTOCOL_ERROR, reason, new Callback.Adapter() + { + @Override + public void failed(Throwable x) + { + ((ISession)session).disconnect(); + } + }); + } } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index a0df3ce9c1f..fced76c03a9 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -21,6 +21,8 @@ package org.eclipse.jetty.http2.server; import java.util.Collections; import java.util.Map; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.FlowControl; import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.IStream; @@ -29,6 +31,7 @@ import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.ServerParser; @@ -66,17 +69,32 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis @Override public boolean onHeaders(HeadersFrame frame) { - IStream stream = createRemoteStream(frame); - if (stream != null) + MetaData metaData = frame.getMetaData(); + if (metaData.isRequest()) { - stream.updateClose(frame.isEndStream(), false); - stream.process(frame, Callback.Adapter.INSTANCE); - Stream.Listener listener = notifyNewStream(stream, frame); - stream.setListener(listener); - // The listener may have sent a frame that closed the stream. - if (stream.isClosed()) - removeStream(stream, false); + IStream stream = createRemoteStream(frame.getStreamId()); + if (stream != null) + { + stream.updateClose(frame.isEndStream(), false); + stream.process(frame, Callback.Adapter.INSTANCE); + Stream.Listener listener = notifyNewStream(stream, frame); + stream.setListener(listener); + // The listener may have sent a frame that closed the stream. + if (stream.isClosed()) + removeStream(stream, false); + } } + else + { + onConnectionFailure(ErrorCodes.INTERNAL_ERROR, "invalid_request"); + } + return false; + } + + @Override + public boolean onPushPromise(PushPromiseFrame frame) + { + onConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "push_promise"); return false; } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 2bd2ef98cb7..1160212541d 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -21,13 +21,13 @@ package org.eclipse.jetty.http2.server; import java.io.IOException; import java.nio.ByteBuffer; -import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -63,16 +63,9 @@ public class HttpChannelOverHTTP2 extends HttpChannel return _expect100Continue; } - public void onHeadersFrame(HeadersFrame frame) + public void onRequest(HeadersFrame frame) { - MetaData metaData = frame.getMetaData(); - if (!metaData.isRequest()) - { - onBadMessage(400, null); - return; - } - - MetaData.Request request = (MetaData.Request)metaData; + MetaData.Request request = (MetaData.Request)frame.getMetaData(); HttpFields fields = request.getFields(); _expect100Continue = fields.contains(HttpHeader.EXPECT,HttpHeaderValue.CONTINUE.asString()); @@ -91,7 +84,22 @@ public class HttpChannelOverHTTP2 extends HttpChannel if (LOG.isDebugEnabled()) { LOG.debug("HTTP2 Request #{}:{}{} {} {}{}{}", - stream.getId(), System.lineSeparator(), request.getMethod(), request.getURI(), request.getVersion(), System.lineSeparator(), fields); + stream.getId(), System.lineSeparator(), request.getMethod(), request.getURI(), request.getVersion(), + System.lineSeparator(), fields); + } + + execute(this); + } + + public void onPushRequest(MetaData.Request request) + { + onRequest(request); + + if (LOG.isDebugEnabled()) + { + LOG.debug("HTTP2 Push Request #{}:{}{} {} {}{}{}", + stream.getId(), System.lineSeparator(), request.getMethod(), request.getURI(), request.getVersion(), + System.lineSeparator(), request.getFields()); } execute(this); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 86f37c83e0e..b0e5b48826c 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -26,11 +26,17 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.IStream; +import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -40,11 +46,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport private final AtomicBoolean commit = new AtomicBoolean(); private final Callback commitCallback = new CommitCallback(); + private final Connector connector; + private final HttpConfiguration httpConfiguration; + private final EndPoint endPoint; private final IStream stream; - private final HeadersFrame request; + private final MetaData.Request request; - public HttpTransportOverHTTP2(IStream stream, HeadersFrame request) + public HttpTransportOverHTTP2(Connector connector, HttpConfiguration httpConfiguration, EndPoint endPoint, IStream stream, MetaData.Request request) { + this.connector = connector; + this.httpConfiguration = httpConfiguration; + this.endPoint = endPoint; this.stream = stream; this.request = request; } @@ -52,8 +64,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { - MetaData.Request metaData = (MetaData.Request)request.getMetaData(); - boolean isHeadRequest = HttpMethod.HEAD.is(metaData.getMethod()); + boolean isHeadRequest = HttpMethod.HEAD.is(request.getMethod()); // info != null | content != 0 | last = true => commit + send/end // info != null | content != 0 | last = false => commit + send @@ -86,14 +97,30 @@ public class HttpTransportOverHTTP2 implements HttpTransport } } - /** - * @see org.eclipse.jetty.server.HttpTransport#push(org.eclipse.jetty.http.MetaData.Request) - */ @Override - public void push(org.eclipse.jetty.http.MetaData.Request request) - { - // TODO implement push - LOG.warn("NOT YET IMPLEMENTED push in {}",this); + public void push(final MetaData.Request request) + { + stream.push(new PushPromiseFrame(stream.getId(), 0, request), new Promise<Stream>() + { + @Override + public void succeeded(Stream pushStream) + { + HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2(connector, httpConfiguration, endPoint, (IStream)pushStream, request); + HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); + HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input, pushStream); + pushStream.setAttribute(IStream.CHANNEL_ATTRIBUTE, channel); + + channel.onPushRequest(request); + } + + @Override + public void failed(Throwable x) + { + if (LOG.isDebugEnabled()) + LOG.debug("Could not push " + request, x); + stream.getSession().disconnect(); + } + }); } private void commit(HttpGenerator.ResponseInfo info, boolean endStream, Callback callback) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java index 09af845edc0..bdeec795b59 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java @@ -22,7 +22,8 @@ package org.eclipse.jetty.servlets; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; - +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -30,6 +31,7 @@ import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -41,8 +43,6 @@ import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - -/* ------------------------------------------------------------ */ /** * A filter that builds a cache of associated resources to push * using the following heuristics:<ul> @@ -53,135 +53,133 @@ import org.eclipse.jetty.util.log.Logger; * <li>If the time period between a request and an associated request is small, * that indicates a possible push resource * </ul> - * */ public class PushCacheFilter implements Filter { private static final Logger LOG = Log.getLogger(PushCacheFilter.class); - private final ConcurrentMap<String, Target> _cache = new ConcurrentHashMap<>(); + + private final ConcurrentMap<String, PrimaryResource> _cache = new ConcurrentHashMap<>(); + private long _associatePeriod = 2000L; - private long _associateDelay=2000L; - - /* ------------------------------------------------------------ */ - /** - * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) - */ @Override public void init(FilterConfig config) throws ServletException { - if (config.getInitParameter("associateDelay")!=null) - _associateDelay=Long.valueOf(config.getInitParameter("associateDelay")); + if (config.getInitParameter("associateDelay") != null) + _associatePeriod = Long.valueOf(config.getInitParameter("associateDelay")); } - /* ------------------------------------------------------------ */ - /** - * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) - */ @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException - { - Request baseRequest = Request.getBaseRequest(request); - - + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException + { + HttpServletRequest request = (HttpServletRequest)req; + // Iterating over fields is more efficient than multiple gets - HttpFields fields = baseRequest.getHttpFields(); - boolean conditional=false; - String referer=null; - loop: for (int i=0;i<fields.size();i++) + HttpFields fields = Request.getBaseRequest(req).getHttpFields(); + boolean conditional = false; + String referrer = null; + loop: for (int i = 0; i < fields.size(); i++) { - HttpField field=fields.getField(i); - HttpHeader header=field.getHeader(); - if (header==null) + HttpField field = fields.getField(i); + HttpHeader header = field.getHeader(); + if (header == null) continue; - + switch (header) { case IF_MATCH: case IF_MODIFIED_SINCE: case IF_NONE_MATCH: case IF_UNMODIFIED_SINCE: - conditional=true; + conditional = true; break loop; - + case REFERER: - referer=field.getValue(); + referrer = field.getValue(); break; - + default: break; } } if (LOG.isDebugEnabled()) - LOG.debug("{} {} referer={} conditional={}%n",baseRequest.getMethod(),baseRequest.getRequestURI(),referer,conditional); + LOG.debug("{} {} referrer={} conditional={}", request.getMethod(), request.getRequestURI(), referrer, conditional); - HttpURI uri = null; if (!conditional) { - String session = baseRequest.getSession(true).getId(); - String path = URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo()); - - if (referer!=null) + String path = URIUtil.addPaths(request.getServletPath(), request.getPathInfo()); + + if (referrer != null) { - uri = new HttpURI(referer); - if (request.getServerName().equals(uri.getHost())) + HttpURI referrerURI = new HttpURI(referrer); + if (request.getServerName().equals(referrerURI.getHost()) && + request.getServerPort() == referrerURI.getPort()) { - String from = uri.getPath(); - if (from.startsWith(baseRequest.getContextPath())) + String referrerPath = referrerURI.getPath(); + if (referrerPath.startsWith(request.getContextPath())) { - String from_in_ctx = from.substring(baseRequest.getContextPath().length()); - - Target target = _cache.get(from_in_ctx); - if (target!=null) + String referrerPathNoContext = referrerPath.substring(request.getContextPath().length()); + PrimaryResource primaryResource = _cache.get(referrerPathNoContext); + if (primaryResource != null) { - Long last = target._timestamp.get(session); - if (last!=null && (System.currentTimeMillis()-last)<_associateDelay && !target._associated.containsKey(path)) + long primaryTimestamp = primaryResource._timestamp.get(); + if (primaryTimestamp != 0) { - RequestDispatcher dispatcher = baseRequest.getServletContext().getRequestDispatcher(path); - if (target._associated.putIfAbsent(path,dispatcher)==null) - LOG.info("ASSOCIATE {}->{}",from_in_ctx,dispatcher); + RequestDispatcher dispatcher = request.getServletContext().getRequestDispatcher(path); + if (System.nanoTime() - primaryTimestamp < TimeUnit.MILLISECONDS.toNanos(_associatePeriod)) + { + if (primaryResource._associated.putIfAbsent(path, dispatcher) == null) + { + if (LOG.isDebugEnabled()) + LOG.debug("Associated {} -> {}", referrerPathNoContext, dispatcher); + } + } + else + { + if (LOG.isDebugEnabled()) + LOG.debug("Not associated {} -> {}, outside associate period of {}ms", referrerPathNoContext, dispatcher, _associatePeriod); + } } } } } } - // push some resources? - Target target = _cache.get(path); - if (target == null) + // Push some resources? + PrimaryResource primaryResource = _cache.get(path); + if (primaryResource == null) { - Target t=new Target(); - target = _cache.putIfAbsent(path,t); - target = target==null?t:target; + PrimaryResource t = new PrimaryResource(); + primaryResource = _cache.putIfAbsent(path, t); + primaryResource = primaryResource == null ? t : primaryResource; + primaryResource._timestamp.compareAndSet(0, System.nanoTime()); + if (LOG.isDebugEnabled()) + LOG.debug("Cached {}", path); } - target._timestamp.put(session,System.currentTimeMillis()); - if (target._associated.size()>0) + + if (!primaryResource._associated.isEmpty()) { - for (RequestDispatcher dispatcher : target._associated.values()) + for (RequestDispatcher dispatcher : primaryResource._associated.values()) { - LOG.info("PUSH {}->{}",path,dispatcher); + if (LOG.isDebugEnabled()) + LOG.debug("Pushing {} <- {}", dispatcher, path); ((Dispatcher)dispatcher).push(request); } } } - chain.doFilter(request,response); - + chain.doFilter(req, resp); } - /* ------------------------------------------------------------ */ - /** - * @see javax.servlet.Filter#destroy() - */ @Override public void destroy() - { + { + _cache.clear(); } - - public static class Target + private static class PrimaryResource { - final ConcurrentMap<String,RequestDispatcher> _associated = new ConcurrentHashMap<>(); - final ConcurrentMap<String,Long> _timestamp = new ConcurrentHashMap<>(); + private final ConcurrentMap<String, RequestDispatcher> _associated = new ConcurrentHashMap<>(); + private final AtomicLong _timestamp = new AtomicLong(); } } From b47f9ef60522ad435d516741646e8e9acf2a6302 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 15 Aug 2014 19:35:49 +1000 Subject: [PATCH 237/269] cleaned up OSGi manifest creation --- apache-jstl/pom.xml | 3 ++ examples/async-rest/async-rest-jar/pom.xml | 3 ++ examples/embedded/pom.xml | 3 ++ examples/quickstart/pom.xml | 3 ++ jetty-alpn/jetty-alpn-client/pom.xml | 9 ----- jetty-alpn/jetty-alpn-server/pom.xml | 27 -------------- jetty-annotations/pom.xml | 12 ------ jetty-ant/pom.xml | 3 ++ jetty-client/pom.xml | 10 ----- jetty-continuation/pom.xml | 29 --------------- jetty-deploy/pom.xml | 12 ------ jetty-http-spi/pom.xml | 29 --------------- jetty-http/pom.xml | 28 -------------- jetty-http2/http2-client/pom.xml | 32 ++-------------- jetty-http2/http2-common/pom.xml | 32 ++-------------- jetty-http2/http2-hpack/pom.xml | 31 ++-------------- jetty-http2/http2-server/pom.xml | 30 ++------------- jetty-http2/pom.xml | 32 ---------------- jetty-io/pom.xml | 29 --------------- jetty-jaas/pom.xml | 9 ----- jetty-jaspi/pom.xml | 32 +--------------- jetty-jmx/pom.xml | 29 --------------- jetty-jndi/pom.xml | 29 --------------- jetty-jsp/pom.xml | 3 ++ jetty-jspc-maven-plugin/pom.xml | 1 + jetty-maven-plugin/pom.xml | 1 + jetty-monitor/pom.xml | 29 --------------- jetty-nosql/pom.xml | 34 ----------------- jetty-npn/jetty-npn-client/pom.xml | 9 ----- jetty-npn/jetty-npn-server/pom.xml | 27 -------------- jetty-osgi/jetty-osgi-alpn/pom.xml | 34 +++++++---------- jetty-osgi/jetty-osgi-npn/pom.xml | 37 ++++++++----------- .../osgi/test/TestJettyOSGiBootSpdy.java | 9 +++-- .../osgi/test/TestJettyOSGiBootWithJsp.java | 2 + jetty-overlay-deployer/pom.xml | 1 + jetty-plus/pom.xml | 9 ----- jetty-proxy/pom.xml | 29 --------------- jetty-quickstart/pom.xml | 3 ++ jetty-rewrite/pom.xml | 29 --------------- jetty-runner/pom.xml | 1 + jetty-security/pom.xml | 12 ------ jetty-server/pom.xml | 11 ------ jetty-servlet/pom.xml | 8 ---- jetty-servlets/pom.xml | 29 --------------- jetty-spdy/pom.xml | 10 ----- jetty-spdy/spdy-alpn-tests/pom.xml | 4 ++ jetty-spdy/spdy-client/pom.xml | 8 +++- jetty-spdy/spdy-core/pom.xml | 21 +++++++++++ jetty-spdy/spdy-example-webapp/pom.xml | 3 ++ jetty-spdy/spdy-http-client-transport/pom.xml | 1 - jetty-spdy/spdy-http-common/pom.xml | 2 +- jetty-spdy/spdy-http-server/pom.xml | 14 ++++--- jetty-spdy/spdy-npn-tests/pom.xml | 3 ++ jetty-spdy/spdy-server/pom.xml | 8 +++- jetty-spring/pom.xml | 1 + jetty-start/pom.xml | 7 ++-- jetty-util-ajax/pom.xml | 29 --------------- jetty-util/pom.xml | 12 ------ jetty-webapp/pom.xml | 31 ---------------- jetty-websocket/pom.xml | 10 ----- jetty-websocket/websocket-server/pom.xml | 3 +- jetty-websocket/websocket-servlet/pom.xml | 17 --------- jetty-xml/pom.xml | 24 ------------ pom.xml | 26 +++++++++++++ tests/test-continuation/pom.xml | 3 ++ tests/test-integration/pom.xml | 2 + tests/test-loginservice/pom.xml | 3 ++ .../test-sessions/test-hash-sessions/pom.xml | 3 ++ .../test-sessions/test-jdbc-sessions/pom.xml | 3 ++ .../test-mongodb-sessions/pom.xml | 3 ++ .../test-sessions-common/pom.xml | 3 ++ .../test-webapps/test-dispatch-webapp/pom.xml | 3 ++ tests/test-webapps/test-jaas-webapp/pom.xml | 3 ++ tests/test-webapps/test-jetty-webapp/pom.xml | 22 ++++++----- tests/test-webapps/test-jndi-webapp/pom.xml | 3 ++ .../test-webapps/test-mock-resources/pom.xml | 9 ++--- tests/test-webapps/test-proxy-webapp/pom.xml | 3 ++ .../test-container-initializer/pom.xml | 3 ++ .../test-spec-webapp/pom.xml | 3 ++ .../test-web-fragment/pom.xml | 3 ++ .../test-webapps/test-webapp-rfc2616/pom.xml | 3 ++ 81 files changed, 220 insertions(+), 863 deletions(-) diff --git a/apache-jstl/pom.xml b/apache-jstl/pom.xml index 93628bf57dd..051b2b4dc89 100644 --- a/apache-jstl/pom.xml +++ b/apache-jstl/pom.xml @@ -9,6 +9,9 @@ <name>Apache :: JSTL module</name> <url>http://tomcat.apache.org/taglibs/standard/</url> <packaging>jar</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.apache.jstl</bundle-symbolic-name> + </properties> <build> <plugins> diff --git a/examples/async-rest/async-rest-jar/pom.xml b/examples/async-rest/async-rest-jar/pom.xml index e9d5220edc0..b105a911d86 100644 --- a/examples/async-rest/async-rest-jar/pom.xml +++ b/examples/async-rest/async-rest-jar/pom.xml @@ -10,6 +10,9 @@ <packaging>jar</packaging> <name>Example Async Rest :: Jar</name> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.examples.asyc.rest</bundle-symbolic-name> + </properties> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/examples/embedded/pom.xml b/examples/embedded/pom.xml index 760ef797d7e..35240bd3d7f 100644 --- a/examples/embedded/pom.xml +++ b/examples/embedded/pom.xml @@ -11,6 +11,9 @@ <name>Example :: Jetty Embedded</name> <description>Jetty Embedded Examples</description> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.examples.embedded</bundle-symbolic-name> + </properties> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/examples/quickstart/pom.xml b/examples/quickstart/pom.xml index 9a1cc7c3c25..f8596181082 100644 --- a/examples/quickstart/pom.xml +++ b/examples/quickstart/pom.xml @@ -11,6 +11,9 @@ <name>Example :: Jetty Quick Start</name> <description>Jetty Quick Start Example</description> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.examples.quickstart</bundle-symbolic-name> + </properties> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/jetty-alpn/jetty-alpn-client/pom.xml b/jetty-alpn/jetty-alpn-client/pom.xml index 63c74b64bee..1946bebfafc 100644 --- a/jetty-alpn/jetty-alpn-client/pom.xml +++ b/jetty-alpn/jetty-alpn-client/pom.xml @@ -29,15 +29,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature with a snapshot. --> <plugin> diff --git a/jetty-alpn/jetty-alpn-server/pom.xml b/jetty-alpn/jetty-alpn-server/pom.xml index ad0b78f7185..dff18787e17 100644 --- a/jetty-alpn/jetty-alpn-server/pom.xml +++ b/jetty-alpn/jetty-alpn-server/pom.xml @@ -12,33 +12,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>org.eclipse.jetty.alpn,*</Import-Package> - <_nouses>true</_nouses> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index b0522b04edb..e8199c053e3 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -50,18 +50,6 @@ </execution> </executions> </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-ant/pom.xml b/jetty-ant/pom.xml index 300b5013dbb..ea9b556fa4e 100644 --- a/jetty-ant/pom.xml +++ b/jetty-ant/pom.xml @@ -9,6 +9,9 @@ <packaging>jar</packaging> <name>Jetty :: Ant Plugin</name> + <properties> + <bundle-symbolic-name>org.eclipse.jetty.ant</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index b0d773c79e3..b6e9bfea9d5 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -49,16 +49,6 @@ </execution> </executions> </plugin> - <!-- Required for OSGI --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index 5fd2ee0a3f3..7a0ae48c372 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -14,35 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <id>artifact-jar</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index fbdff7dbbd9..58cc708480f 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -49,18 +49,6 @@ </execution> </executions> </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml index 9706bdde775..c4a22f75f27 100644 --- a/jetty-http-spi/pom.xml +++ b/jetty-http-spi/pom.xml @@ -32,35 +32,6 @@ </dependencies> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <id>artifact-jar</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index d7c288ca103..26275c1ca20 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -26,33 +26,10 @@ </dependencies> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <executions> - <execution> - <id>artifact-jar</id> - <goals> - <goal>jar</goal> - </goals> - </execution> <execution> <id>test-jar</id> <goals> @@ -60,11 +37,6 @@ </goals> </execution> </executions> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> diff --git a/jetty-http2/http2-client/pom.xml b/jetty-http2/http2-client/pom.xml index 0f5372000de..7090fec993a 100644 --- a/jetty-http2/http2-client/pom.xml +++ b/jetty-http2/http2-client/pom.xml @@ -12,35 +12,11 @@ <artifactId>http2-client</artifactId> <name>Jetty :: HTTP2 :: Client</name> + <properties> + <bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name> + </properties> + <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> - </plugins> </build> <dependencies> diff --git a/jetty-http2/http2-common/pom.xml b/jetty-http2/http2-common/pom.xml index 2a8baffa5cc..f0b727025ee 100644 --- a/jetty-http2/http2-common/pom.xml +++ b/jetty-http2/http2-common/pom.xml @@ -23,35 +23,11 @@ </dependency> </dependencies> + <properties> + <bundle-symbolic-name>${project.groupId}.common</bundle-symbolic-name> + </properties> + <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> - </plugins> </build> </project> diff --git a/jetty-http2/http2-hpack/pom.xml b/jetty-http2/http2-hpack/pom.xml index 0ae0e947ac0..8178a67f327 100644 --- a/jetty-http2/http2-hpack/pom.xml +++ b/jetty-http2/http2-hpack/pom.xml @@ -10,6 +10,9 @@ <artifactId>http2-hpack</artifactId> <name>Jetty :: HTTP2 :: HPACK</name> + <properties> + <bundle-symbolic-name>${project.groupId}.hpack</bundle-symbolic-name> + </properties> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> @@ -40,34 +43,6 @@ </dependencies> <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> - </plugins> </build> </project> diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index df00ecba344..8582fd37b3a 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -12,6 +12,10 @@ <artifactId>http2-server</artifactId> <name>Jetty :: HTTP2 :: Server</name> + <properties> + <bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name> + </properties> + <build> <plugins> <plugin> @@ -31,32 +35,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> </plugins> </build> diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index 0e6574e1a7d..0afe6331b6d 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -19,37 +19,5 @@ <module>http2-server</module> </modules> - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Export-Package>org.eclipse.jetty.http2.*"</Export-Package> - <Import-Package>org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> - <_nouses>true</_nouses> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> - </plugins> - </build> </project> diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index 3b94edde47d..f14faf79ae2 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -30,35 +30,6 @@ </dependencies> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <id>artifact-jar</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-jaas/pom.xml b/jetty-jaas/pom.xml index 04e827fbbe0..a8393bf9725 100644 --- a/jetty-jaas/pom.xml +++ b/jetty-jaas/pom.xml @@ -33,15 +33,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index 37b062b7688..b476e0bcc30 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -10,7 +10,7 @@ <description>Jetty security infrastructure</description> <url>http://www.eclipse.org/jetty</url> <properties> - <bundle-symbolic-name>${project.groupId}.jaspi</bundle-symbolic-name> + <bundle-symbolic-name>${project.groupId}.security.jaspi</bundle-symbolic-name> </properties> <build> <plugins> @@ -31,36 +31,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package> - <Export-Package>org.eclipse.jetty.security.jaspi.*;version="${parsedVersion.osgiVersion}"</Export-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index e56bdadcf91..66646534379 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -14,35 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.management.*,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index 70a88f0c7f6..1f2ba5fa77f 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -31,35 +31,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.naming.*,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml index 9c279dcc714..52d71e58f35 100644 --- a/jetty-jsp/pom.xml +++ b/jetty-jsp/pom.xml @@ -9,6 +9,9 @@ <name>Jetty :: JSP dependencies</name> <url>http://www.eclipse.org/jetty</url> <packaging>jar</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.glassfish.jsp.parent</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/jetty-jspc-maven-plugin/pom.xml b/jetty-jspc-maven-plugin/pom.xml index 015d5bf1096..853f6f59d83 100644 --- a/jetty-jspc-maven-plugin/pom.xml +++ b/jetty-jspc-maven-plugin/pom.xml @@ -9,6 +9,7 @@ <packaging>maven-plugin</packaging> <name>Jetty :: Jetty JSPC Maven Plugin</name> <properties> + <bundle-symbolic-name>${project.groupId}.jspc.plugin</bundle-symbolic-name> </properties> <build> <plugins> diff --git a/jetty-maven-plugin/pom.xml b/jetty-maven-plugin/pom.xml index ea5274870af..baa1ba72655 100644 --- a/jetty-maven-plugin/pom.xml +++ b/jetty-maven-plugin/pom.xml @@ -11,6 +11,7 @@ <properties> <mavenVersion>3.0.3</mavenVersion> <pluginToolsVersion>3.1</pluginToolsVersion> + <bundle-symbolic-name>${project.groupId}.maven.plugin</bundle-symbolic-name> </properties> <build> <plugins> diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index 034b9e4d7eb..1a0dedee79c 100644 --- a/jetty-monitor/pom.xml +++ b/jetty-monitor/pom.xml @@ -31,35 +31,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.management.*,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index 92c7d77fd09..a04cfefd1e8 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -31,40 +31,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.server.session.jmx;resolution:=optional,org.eclipse.jetty.*,*</Import-Package> - </instructions> - </configuration> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <id>artifact-jar</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> </plugins> </build> <dependencies> diff --git a/jetty-npn/jetty-npn-client/pom.xml b/jetty-npn/jetty-npn-client/pom.xml index 26aab23bfad..1a7b8d67e48 100644 --- a/jetty-npn/jetty-npn-client/pom.xml +++ b/jetty-npn/jetty-npn-client/pom.xml @@ -29,15 +29,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature with a snapshot. --> <plugin> diff --git a/jetty-npn/jetty-npn-server/pom.xml b/jetty-npn/jetty-npn-server/pom.xml index a2d18dff8da..b887a07481b 100644 --- a/jetty-npn/jetty-npn-server/pom.xml +++ b/jetty-npn/jetty-npn-server/pom.xml @@ -12,33 +12,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>org.eclipse.jetty.npn,*</Import-Package> - <_nouses>true</_nouses> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-osgi/jetty-osgi-alpn/pom.xml b/jetty-osgi/jetty-osgi-alpn/pom.xml index b863f69f663..5becb089c11 100644 --- a/jetty-osgi/jetty-osgi-alpn/pom.xml +++ b/jetty-osgi/jetty-osgi-alpn/pom.xml @@ -14,34 +14,26 @@ <build> <plugins> <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <version>1.7</version> - <executions> - <execution> - <id>parse-version</id> - <goals> - <goal>parse-version</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> <configuration> - <archive> - <manifestEntries> - <Bundle-ManifestVersion>2</Bundle-ManifestVersion> + <instructions> <Bundle-SymbolicName>${bundle-symbolic-name};singleton:=true</Bundle-SymbolicName> <Bundle-Name>Jetty OSGi ALPN Fragment</Bundle-Name> - <Bundle-Version>${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}</Bundle-Version> + <Import-Package>!javax.*;!org.eclipse.jetty.*</Import-Package> <Export-Package>org.eclipse.jetty.alpn;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package> <Fragment-Host>system.bundle;extension:=framework</Fragment-Host> - </manifestEntries> - </archive> + </instructions> </configuration> </plugin> </plugins> </build> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.alpn</groupId> + <artifactId>alpn-api</artifactId> + <version>${alpn.api.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> </project> diff --git a/jetty-osgi/jetty-osgi-npn/pom.xml b/jetty-osgi/jetty-osgi-npn/pom.xml index a19818e04ae..265351b835c 100644 --- a/jetty-osgi/jetty-osgi-npn/pom.xml +++ b/jetty-osgi/jetty-osgi-npn/pom.xml @@ -14,34 +14,27 @@ <build> <plugins> <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <version>1.7</version> - <executions> - <execution> - <id>parse-version</id> - <goals> - <goal>parse-version</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> <configuration> - <archive> - <manifestEntries> - <Bundle-ManifestVersion>2</Bundle-ManifestVersion> + <instructions> <Bundle-SymbolicName>${bundle-symbolic-name};singleton:=true</Bundle-SymbolicName> <Bundle-Name>Jetty OSGi NPN Fragment</Bundle-Name> - <Bundle-Version>${parsedVersion.osgiVersion}</Bundle-Version> - <Export-Package>org.eclipse.jetty.npn</Export-Package> + <Bundle-Description>${project.name}</Bundle-Description> + <Import-Package>!javax.*,!org.eclipse.jetty.*</Import-Package> + <Export-Package>org.eclipse.jetty.npn;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package> <Fragment-Host>system.bundle;extension:=framework</Fragment-Host> - </manifestEntries> - </archive> + </instructions> </configuration> </plugin> </plugins> </build> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.npn</groupId> + <artifactId>npn-api</artifactId> + <version>${npn.api.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> </project> diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java index df05da81575..4e3a3a5d278 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java @@ -44,7 +44,7 @@ import org.osgi.framework.BundleContext; * SPDY setup. */ @RunWith(PaxExam.class) -@Ignore +//@Ignore public class TestJettyOSGiBootSpdy { private static final String LOG_LEVEL = "WARN"; @@ -69,6 +69,8 @@ public class TestJettyOSGiBootSpdy options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.util.component.LEVEL").value("DEBUG")))); options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.server.LEVEL").value("DEBUG")))); options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.xml.LEVEL").value("INFO")))); + // options.addAll(Arrays.asList(options(systemProperty("osgi.console").value("6666")))); + // options.addAll(Arrays.asList(options(systemProperty("osgi.console.enable.builtin").value("true")))); return options.toArray(new Option[options.size()]); } @@ -108,14 +110,15 @@ public class TestJettyOSGiBootSpdy @Test public void assertAllBundlesActiveOrResolved() { - TestOSGiUtil.debugBundles(bundleContext); + // TestOSGiUtil.debugBundles(bundleContext); TestOSGiUtil.assertAllBundlesActiveOrResolved(bundleContext); } @Test public void testSpdyOnHttpService() throws Exception { - TestOSGiUtil.debugBundles(bundleContext); + // TestOSGiUtil.debugBundles(bundleContext); + // Thread.sleep(2000000000); TestOSGiUtil.testHttpServiceGreetings(bundleContext, "https", TestJettyOSGiBootCore.DEFAULT_SSL_PORT); } diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java index 0032744e4b8..6b703cee13d 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java @@ -146,11 +146,13 @@ public class TestJettyOSGiBootWithJsp @Test public void testJspDump() throws Exception { + // TestOSGiUtil.debugBundles(bundleContext); HttpClient client = new HttpClient(); try { client.start(); ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/jsp/dump.jsp"); + assertEquals(HttpStatus.OK_200, response.getStatus()); String content = new String(response.getContent()); diff --git a/jetty-overlay-deployer/pom.xml b/jetty-overlay-deployer/pom.xml index a531f464f59..9f0a73b98c5 100644 --- a/jetty-overlay-deployer/pom.xml +++ b/jetty-overlay-deployer/pom.xml @@ -10,6 +10,7 @@ <description>Overlayed deployer</description> <url>http://www.eclipse.org/jetty</url> <properties> + <bundle-symbolic-name>${project.groupId}.overlays</bundle-symbolic-name> </properties> <build> <plugins> diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index c7eadc372a5..7999c68ecdd 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -34,15 +34,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-proxy/pom.xml b/jetty-proxy/pom.xml index d2550a20fa0..36612da4d45 100644 --- a/jetty-proxy/pom.xml +++ b/jetty-proxy/pom.xml @@ -14,35 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-quickstart/pom.xml b/jetty-quickstart/pom.xml index a67e95337dd..2e5e2b6cf36 100644 --- a/jetty-quickstart/pom.xml +++ b/jetty-quickstart/pom.xml @@ -10,6 +10,9 @@ <name>Jetty :: Quick Start</name> <description>Jetty Quick Start</description> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.quickstart</bundle-symbolic-name> + </properties> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index 578009f528c..99150972892 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -14,35 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-runner/pom.xml b/jetty-runner/pom.xml index 7c7350d2cd9..a64b6ebf845 100644 --- a/jetty-runner/pom.xml +++ b/jetty-runner/pom.xml @@ -10,6 +10,7 @@ <properties> <assembly-directory>target/distribution</assembly-directory> + <bundle-symbolic-name>${project.groupId}.runner</bundle-symbolic-name> </properties> <url>http://www.eclipse.org/jetty</url> <build> diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index e3361f53c75..480e2ff2256 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -49,18 +49,6 @@ </execution> </executions> </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index c01cb9a7668..0a200a105d7 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -37,12 +37,6 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <executions> - <execution> - <id>artifact-jar</id> - <goals> - <goal>jar</goal> - </goals> - </execution> <execution> <id>test-jar</id> <goals> @@ -50,11 +44,6 @@ </goals> </execution> </executions> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index 1bcc0866838..73bc85058ee 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -34,16 +34,8 @@ </executions> </plugin> <plugin> - <!-- - Required for OSGI - --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> <executions> <execution> <id>tests</id> diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index 4acf0c8f55a..98bfefdf14a 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -15,35 +15,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index a4890554183..83eee349205 100644 --- a/jetty-spdy/pom.xml +++ b/jetty-spdy/pom.xml @@ -55,7 +55,6 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.*</Export-Package> <Import-Package>org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <_nouses>true</_nouses> </instructions> @@ -63,15 +62,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> </plugins> </build> diff --git a/jetty-spdy/spdy-alpn-tests/pom.xml b/jetty-spdy/spdy-alpn-tests/pom.xml index 0d02b5054c7..1c0b55f2542 100644 --- a/jetty-spdy/spdy-alpn-tests/pom.xml +++ b/jetty-spdy/spdy-alpn-tests/pom.xml @@ -9,6 +9,10 @@ <modelVersion>4.0.0</modelVersion> <artifactId>spdy-alpn-tests</artifactId> <name>Jetty :: SPDY :: ALPN Tests</name> + <properties> + <bundle-symbolic-name>${project.groupId}.alpn.tests</bundle-symbolic-name> + </properties> + <build> <plugins> diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml index 4784dd7d271..14569025fa7 100644 --- a/jetty-spdy/spdy-client/pom.xml +++ b/jetty-spdy/spdy-client/pom.xml @@ -28,8 +28,12 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.client</Export-Package> - <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.npn.client;resolution:=optional,!org.eclipse.jetty.alpn,org.eclipse.jetty.alpn.client;resolution:=optional,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> + <Import-Package> + !org.eclipse.jetty.npn, + org.eclipse.jetty.npn.client;resolution:=optional;version="[9.0,10.0)", + !org.eclipse.jetty.alpn, + org.eclipse.jetty.alpn.client;resolution:=optional;version="[9.0,10.0)", + org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> </instructions> </configuration> </execution> diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml index 047b1799203..38760a1e7b4 100644 --- a/jetty-spdy/spdy-core/pom.xml +++ b/jetty-spdy/spdy-core/pom.xml @@ -13,6 +13,27 @@ <properties> <bundle-symbolic-name>${project.groupId}.core</bundle-symbolic-name> </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <executions> + <execution> + <goals> + <goal>manifest</goal> + </goals> + <configuration> + <instructions> + <Export-Package>org.eclipse.jetty.spdy.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package> + </instructions> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> <dependencies> <dependency> diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml index 4a25712d6ad..bdda6079d46 100644 --- a/jetty-spdy/spdy-example-webapp/pom.xml +++ b/jetty-spdy/spdy-example-webapp/pom.xml @@ -9,6 +9,9 @@ <artifactId>spdy-example-webapp</artifactId> <packaging>war</packaging> <name>Jetty :: SPDY :: HTTP Web Application</name> + <properties> + <bundle-symbolic-name>${project.groupId}.example.webapp</bundle-symbolic-name> + </properties> <build> <plugins> diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml index 028b99817ea..cb8aed7b189 100644 --- a/jetty-spdy/spdy-http-client-transport/pom.xml +++ b/jetty-spdy/spdy-http-client-transport/pom.xml @@ -27,7 +27,6 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.client.http</Export-Package> <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> </instructions> </configuration> diff --git a/jetty-spdy/spdy-http-common/pom.xml b/jetty-spdy/spdy-http-common/pom.xml index 0857515bd3b..07fd45e93fe 100644 --- a/jetty-spdy/spdy-http-common/pom.xml +++ b/jetty-spdy/spdy-http-common/pom.xml @@ -27,7 +27,7 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.http</Export-Package> + <Export-Package>${project.groupId}.http.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package> <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> </instructions> </configuration> diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml index ffe9f134fe8..148ff92242b 100644 --- a/jetty-spdy/spdy-http-server/pom.xml +++ b/jetty-spdy/spdy-http-server/pom.xml @@ -10,7 +10,7 @@ <name>Jetty :: SPDY :: HTTP Server</name> <properties> - <bundle-symbolic-name>${project.groupId}.http.server</bundle-symbolic-name> + <bundle-symbolic-name>${project.groupId}.server.http</bundle-symbolic-name> </properties> <build> @@ -39,7 +39,6 @@ <execution> <id>artifact-jars</id> <goals> - <goal>jar</goal> <goal>test-jar</goal> </goals> </execution> @@ -56,10 +55,13 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.server.http, - org.eclipse.jetty.spdy.server.proxy;version="9.3" - </Export-Package> - <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",* + <Export-Package> + ${bundle-symbolic-name}.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}", + ${project.groupId}.server.proxy.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package> + <Import-Package> + !org.eclipse.jetty.alpn.*, + !org.eclipse.jetty.npn.*, + org.eclipse.jetty.*;version="[9.0,10.0)",* </Import-Package> <_nouses>true</_nouses> </instructions> diff --git a/jetty-spdy/spdy-npn-tests/pom.xml b/jetty-spdy/spdy-npn-tests/pom.xml index f11d9a0e6d2..3594a6ef30a 100644 --- a/jetty-spdy/spdy-npn-tests/pom.xml +++ b/jetty-spdy/spdy-npn-tests/pom.xml @@ -10,6 +10,9 @@ <artifactId>spdy-npn-tests</artifactId> <name>Jetty :: SPDY :: NPN Tests</name> + <properties> + <bundle-symbolic-name>${project.groupId}.npn.tests</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index 5f8e53972fc..a220717a220 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -28,8 +28,12 @@ </goals> <configuration> <instructions> - <Export-Package>org.eclipse.jetty.spdy.server</Export-Package> - <Import-Package>org.eclipse.jetty.alpn;resolution:=optional,org.eclipse.jetty.alpn.server;resolution:=optional, org.eclipse.jetty.npn;resolution:=optional,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> + <Import-Package> + org.eclipse.jetty.alpn;resolution:=optional;version="[9.0,10.0)", + org.eclipse.jetty.alpn.server;resolution:=optional;version="[9.0,10.0)", + org.eclipse.jetty.npn;resolution:=optional;version="[9.0,10.0)", + org.eclipse.jetty.npn.server;resolution:=optional;version="[9.0,10.0)", + org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <_nouses>true</_nouses> </instructions> </configuration> diff --git a/jetty-spring/pom.xml b/jetty-spring/pom.xml index 0adc885f03c..df362cb6d28 100644 --- a/jetty-spring/pom.xml +++ b/jetty-spring/pom.xml @@ -11,6 +11,7 @@ <properties> <spring-version>3.2.8.RELEASE</spring-version> <dependencies>target/dependencies</dependencies> + <bundle-symbolic-name>${project.groupId}.spring</bundle-symbolic-name> </properties> <build> diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 75cc0e4e3af..a69db463ead 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -9,6 +9,10 @@ <name>Jetty :: Start</name> <description>The start utility</description> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.start</bundle-symbolic-name> + <start-jar-file-name>start.jar</start-jar-file-name> + </properties> <build> <plugins> <plugin> @@ -30,9 +34,6 @@ </plugin> </plugins> </build> - <properties> - <start-jar-file-name>start.jar</start-jar-file-name> - </properties> <dependencies> <dependency> <groupId>org.eclipse.jetty.toolchain</groupId> diff --git a/jetty-util-ajax/pom.xml b/jetty-util-ajax/pom.xml index a0ad0e84109..ee95fe379d0 100644 --- a/jetty-util-ajax/pom.xml +++ b/jetty-util-ajax/pom.xml @@ -14,35 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.slf4j;version="[1.5,2.0)";resolution:=optional,org.slf4j.impl;version="[1.5,2.0)";resolution:=optional,*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <!-- <plugin> <groupId>org.apache.maven.plugins</groupId> diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index f0a4e25a188..c4f991b69b0 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -31,18 +31,6 @@ </execution> </executions> </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index 93b646dda5d..ffbc21d9e4a 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -44,37 +44,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - <configuration> - <instructions> - <Import-Package>javax.servlet.*;version="[2.6.0,3.2]",*</Import-Package> - </instructions> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile> - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - </manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 7a209faeb26..6925879e1bc 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -43,7 +43,6 @@ </goals> <configuration> <instructions> - <Export-Package>${bundle-symbolic-name}.*</Export-Package> <Import-Package>javax.servlet.*;version="[3.0,4.0)",org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <_nouses>true</_nouses> </instructions> @@ -51,15 +50,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>clirr-maven-plugin</artifactId> diff --git a/jetty-websocket/websocket-server/pom.xml b/jetty-websocket/websocket-server/pom.xml index e6338d50d63..76efde8a165 100644 --- a/jetty-websocket/websocket-server/pom.xml +++ b/jetty-websocket/websocket-server/pom.xml @@ -21,9 +21,8 @@ <artifactId>maven-jar-plugin</artifactId> <executions> <execution> - <id>artifact-jars</id> + <id>test-jar</id> <goals> - <goal>jar</goal> <goal>test-jar</goal> </goals> </execution> diff --git a/jetty-websocket/websocket-servlet/pom.xml b/jetty-websocket/websocket-servlet/pom.xml index 97bf9cff6c6..00a90ce7353 100644 --- a/jetty-websocket/websocket-servlet/pom.xml +++ b/jetty-websocket/websocket-servlet/pom.xml @@ -15,23 +15,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <id>artifact-jar</id> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - <configuration> - <archive> - <manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index 6d77d412758..f4ad571ab8a 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -14,30 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <executions> - <execution> - <goals> - <goal>manifest</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <!-- - Required for OSGI - --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/pom.xml b/pom.xml index 68567b05f98..62811d3a1fb 100644 --- a/pom.xml +++ b/pom.xml @@ -236,6 +236,27 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>manifest</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> + </archive> + </configuration> + </plugin> + </plugins> <pluginManagement> <plugins> @@ -284,8 +305,13 @@ <artifactId>maven-bundle-plugin</artifactId> <extensions>true</extensions> <configuration> + <supportedProjectTypes> + <supportedProjectType>jar</supportedProjectType> + <supportedProjectType>maven-plugin</supportedProjectType> + </supportedProjectTypes> <instructions> <Bundle-SymbolicName>${bundle-symbolic-name}</Bundle-SymbolicName> + <Bundle-Description>Jetty module for ${project.name}</Bundle-Description> <Bundle-RequiredExecutionEnvironment>JavaSE-1.7</Bundle-RequiredExecutionEnvironment> <Bundle-DocURL>${jetty.url}</Bundle-DocURL> <Bundle-Vendor>Eclipse Jetty Project</Bundle-Vendor> diff --git a/tests/test-continuation/pom.xml b/tests/test-continuation/pom.xml index 1f7cb0b0450..6a9c8f75fcb 100644 --- a/tests/test-continuation/pom.xml +++ b/tests/test-continuation/pom.xml @@ -28,6 +28,9 @@ <packaging>jar</packaging> <name>Test :: Continuation</name> <description>Asynchronous API</description> + <properties> + <bundle-symbolic-name>${project.groupId}.continuation</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml index e08d8585f5d..dfe8aed823a 100644 --- a/tests/test-integration/pom.xml +++ b/tests/test-integration/pom.xml @@ -31,6 +31,8 @@ <test-wars-dir>${project.build.directory}/test-wars</test-wars-dir> <test-libs-dir>${project.build.directory}/test-libs</test-libs-dir> <test-dist-dir>${project.build.directory}/test-dist</test-dist-dir> + <bundle-symbolic-name>${project.groupId}.integrations</bundle-symbolic-name> + </properties> <build> <plugins> diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml index 75fc5d95035..be9a618fb1a 100644 --- a/tests/test-loginservice/pom.xml +++ b/tests/test-loginservice/pom.xml @@ -26,6 +26,9 @@ <artifactId>test-loginservice</artifactId> <name>Jetty Tests :: Login Service</name> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.loginservice</bundle-symbolic-name> + </properties> <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index d03667ed5e4..ea448116202 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -26,6 +26,9 @@ <artifactId>test-hash-sessions</artifactId> <name>Jetty Tests :: Sessions :: Hash</name> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.sessions.hash</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 39f905d0e88..2d69ff7acc6 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -26,6 +26,9 @@ <artifactId>test-jdbc-sessions</artifactId> <name>Jetty Tests :: Sessions :: JDBC</name> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.sessions.jdbc</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-sessions/test-mongodb-sessions/pom.xml b/tests/test-sessions/test-mongodb-sessions/pom.xml index e08bc42b7ef..30bb7f355ff 100644 --- a/tests/test-sessions/test-mongodb-sessions/pom.xml +++ b/tests/test-sessions/test-mongodb-sessions/pom.xml @@ -26,6 +26,9 @@ <artifactId>test-mongodb-sessions</artifactId> <name>Jetty Tests :: Sessions :: Mongo</name> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.sessions.mongo</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index e608d5d357e..e15e013941b 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -26,6 +26,9 @@ <artifactId>test-sessions-common</artifactId> <name>Jetty Tests :: Sessions :: Common</name> <url>http://www.eclipse.org/jetty</url> + <properties> + <bundle-symbolic-name>${project.groupId}.sessions.common</bundle-symbolic-name> + </properties> <build> </build> <dependencies> diff --git a/tests/test-webapps/test-dispatch-webapp/pom.xml b/tests/test-webapps/test-dispatch-webapp/pom.xml index 497fdd572d6..5afe024043c 100644 --- a/tests/test-webapps/test-dispatch-webapp/pom.xml +++ b/tests/test-webapps/test-dispatch-webapp/pom.xml @@ -9,6 +9,9 @@ <name>Jetty Tests :: Webapps :: Dispatch Webapp</name> <artifactId>test-dispatch-webapp</artifactId> <packaging>war</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.dispatch</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-webapps/test-jaas-webapp/pom.xml b/tests/test-webapps/test-jaas-webapp/pom.xml index 34ab3005e47..7c1e889c73a 100644 --- a/tests/test-webapps/test-jaas-webapp/pom.xml +++ b/tests/test-webapps/test-jaas-webapp/pom.xml @@ -9,6 +9,9 @@ <artifactId>test-jaas-webapp</artifactId> <name>Jetty Tests :: WebApp :: JAAS</name> <packaging>war</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.jaas</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-webapps/test-jetty-webapp/pom.xml b/tests/test-webapps/test-jetty-webapp/pom.xml index 49ee81234c7..5affbf425a6 100644 --- a/tests/test-webapps/test-jetty-webapp/pom.xml +++ b/tests/test-webapps/test-jetty-webapp/pom.xml @@ -29,6 +29,9 @@ <name>Test :: Jetty Test Webapp</name> <url>http://www.eclipse.org/jetty</url> <packaging>war</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.tests.webapp</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> @@ -70,15 +73,6 @@ </execution> </executions> </plugin> - <!-- also make this webapp an osgi bundle --> - <plugin> - <artifactId>maven-war-plugin</artifactId> - <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - </archive> - </configuration> - </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> @@ -97,7 +91,6 @@ </goals> <configuration> <instructions> - <Bundle-SymbolicName>org.eclipse.jetty.test-jetty-webapp</Bundle-SymbolicName> <Import-Package>javax.servlet.jsp.*;version="[2.2.0,3.0)",javax.servlet.*;version="[2.6,3.2)",org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package> <Export-Package>!com.acme*</Export-Package> <!-- the test webapp is configured via a jetty xml file @@ -114,6 +107,15 @@ </execution> </executions> </plugin> + <!-- also make this webapp an osgi bundle --> + <plugin> + <artifactId>maven-war-plugin</artifactId> + <configuration> + <archive> + <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> + </archive> + </configuration> + </plugin> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> diff --git a/tests/test-webapps/test-jndi-webapp/pom.xml b/tests/test-webapps/test-jndi-webapp/pom.xml index dfcea3f6481..4c4e5e27eaf 100644 --- a/tests/test-webapps/test-jndi-webapp/pom.xml +++ b/tests/test-webapps/test-jndi-webapp/pom.xml @@ -9,6 +9,9 @@ <artifactId>test-jndi-webapp</artifactId> <name>Jetty Tests :: WebApp :: JNDI</name> <packaging>war</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.jndi</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-webapps/test-mock-resources/pom.xml b/tests/test-webapps/test-mock-resources/pom.xml index 3083716570b..2e4c2357022 100644 --- a/tests/test-webapps/test-mock-resources/pom.xml +++ b/tests/test-webapps/test-mock-resources/pom.xml @@ -8,6 +8,9 @@ <name>Jetty Tests :: WebApp :: Mock Resources</name> <artifactId>test-mock-resources</artifactId> <packaging>jar</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.mocks</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> @@ -28,12 +31,6 @@ <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependency> -<!-- - <dependency> - <groupId>javax.mail</groupId> - <artifactId>javax.mail-api</artifactId> - </dependency> ---> <dependency> <groupId>org.eclipse.jetty.orbit</groupId> <artifactId>javax.mail.glassfish</artifactId> diff --git a/tests/test-webapps/test-proxy-webapp/pom.xml b/tests/test-webapps/test-proxy-webapp/pom.xml index a3448f8fbab..aca97c050da 100644 --- a/tests/test-webapps/test-proxy-webapp/pom.xml +++ b/tests/test-webapps/test-proxy-webapp/pom.xml @@ -28,6 +28,9 @@ <artifactId>test-proxy-webapp</artifactId> <name>Test :: Jetty Proxy Webapp</name> <packaging>war</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.proxy</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml index 7f5f90cbaf0..b1af392f37c 100644 --- a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml @@ -8,6 +8,9 @@ <artifactId>test-container-initializer</artifactId> <packaging>jar</packaging> <name>Jetty Tests :: WebApp :: Servlet Spec :: ServletContainerInitializer Test Jar</name> + <properties> + <bundle-symbolic-name>${project.groupId}.sci</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml index 7a9dcc3a2e9..a2ae9b9e2cc 100644 --- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml @@ -9,6 +9,9 @@ <name>Jetty Tests :: Webapps :: Spec Webapp</name> <artifactId>test-spec-webapp</artifactId> <packaging>war</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.spec</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml index e9469b8b8a8..64cc72f8b22 100644 --- a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml +++ b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml @@ -9,6 +9,9 @@ <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-web-fragment</artifactId> <packaging>jar</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.fragment</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml index 803813f565c..b7a3e8325ec 100644 --- a/tests/test-webapps/test-webapp-rfc2616/pom.xml +++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml @@ -27,6 +27,9 @@ <name>Jetty Tests :: WebApp :: RFC2616</name> <url>http://www.eclipse.org/jetty</url> <packaging>war</packaging> + <properties> + <bundle-symbolic-name>${project.groupId}.rfc2616</bundle-symbolic-name> + </properties> <build> <plugins> <plugin> From 1c71040eca9c5f94c55cb70b51924115597872cc Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 15 Aug 2014 19:53:52 +1000 Subject: [PATCH 238/269] moved config plugin to profile --- apache-jsp/pom.xml | 17 ----------- apache-jstl/pom.xml | 17 ----------- jetty-alpn/jetty-alpn-server/pom.xml | 17 ----------- jetty-annotations/pom.xml | 17 ----------- jetty-client/pom.xml | 17 ----------- jetty-deploy/pom.xml | 17 ----------- jetty-fcgi/fcgi-server/pom.xml | 16 ---------- jetty-http2/http2-server/pom.xml | 17 ----------- jetty-jaas/pom.xml | 17 ----------- jetty-jaspi/pom.xml | 17 ----------- jetty-jmx/pom.xml | 17 ----------- jetty-jndi/pom.xml | 17 ----------- jetty-jsp/pom.xml | 17 ----------- jetty-monitor/pom.xml | 17 ----------- jetty-nosql/pom.xml | 17 ----------- jetty-npn/jetty-npn-server/pom.xml | 17 ----------- jetty-plus/pom.xml | 17 ----------- jetty-proxy/pom.xml | 17 ----------- jetty-quickstart/pom.xml | 17 ----------- jetty-rewrite/pom.xml | 17 ----------- jetty-security/pom.xml | 17 ----------- jetty-server/pom.xml | 17 ----------- jetty-servlet/pom.xml | 17 ----------- jetty-servlets/pom.xml | 17 ----------- jetty-spdy/spdy-http-server/pom.xml | 17 ----------- jetty-spring/pom.xml | 17 ----------- jetty-util-ajax/pom.xml | 17 ----------- jetty-util/pom.xml | 17 ----------- jetty-webapp/pom.xml | 17 ----------- .../javax-websocket-server-impl/pom.xml | 17 ----------- pom.xml | 30 +++++++++++++++++++ 31 files changed, 30 insertions(+), 509 deletions(-) diff --git a/apache-jsp/pom.xml b/apache-jsp/pom.xml index 1493dea2550..bfd0b92f4c8 100644 --- a/apache-jsp/pom.xml +++ b/apache-jsp/pom.xml @@ -35,23 +35,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> diff --git a/apache-jstl/pom.xml b/apache-jstl/pom.xml index 051b2b4dc89..b6bc20e62de 100644 --- a/apache-jstl/pom.xml +++ b/apache-jstl/pom.xml @@ -15,23 +15,6 @@ <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> diff --git a/jetty-alpn/jetty-alpn-server/pom.xml b/jetty-alpn/jetty-alpn-server/pom.xml index dff18787e17..410ef11ad9b 100644 --- a/jetty-alpn/jetty-alpn-server/pom.xml +++ b/jetty-alpn/jetty-alpn-server/pom.xml @@ -12,23 +12,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature with a snapshot. --> <plugin> diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index e8199c053e3..678e8d7dc68 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -14,23 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index b6e9bfea9d5..af9a8a3cdc0 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -15,23 +15,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index 58cc708480f..13c09f1e5f2 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -32,23 +32,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-fcgi/fcgi-server/pom.xml b/jetty-fcgi/fcgi-server/pom.xml index 1c57cc5c96b..91c096b59f8 100644 --- a/jetty-fcgi/fcgi-server/pom.xml +++ b/jetty-fcgi/fcgi-server/pom.xml @@ -16,22 +16,6 @@ <build> <plugins> - <plugin> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index 8582fd37b3a..9b9a6c1047d 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -18,23 +18,6 @@ <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> diff --git a/jetty-jaas/pom.xml b/jetty-jaas/pom.xml index a8393bf9725..f30c3a8b693 100644 --- a/jetty-jaas/pom.xml +++ b/jetty-jaas/pom.xml @@ -33,23 +33,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature with a snapshot. --> <plugin> diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index b476e0bcc30..398a2f2cb5a 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -14,23 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index 66646534379..3924132cede 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -14,23 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index 1f2ba5fa77f..b916de79c0f 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -14,23 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml index 52d71e58f35..fe40e402b0b 100644 --- a/jetty-jsp/pom.xml +++ b/jetty-jsp/pom.xml @@ -14,23 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index 1a0dedee79c..3ce5b3f4d04 100644 --- a/jetty-monitor/pom.xml +++ b/jetty-monitor/pom.xml @@ -31,23 +31,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index a04cfefd1e8..ff6f0780690 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -14,23 +14,6 @@ <build> <defaultGoal>install</defaultGoal> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> <dependencies> diff --git a/jetty-npn/jetty-npn-server/pom.xml b/jetty-npn/jetty-npn-server/pom.xml index b887a07481b..3c606d34a27 100644 --- a/jetty-npn/jetty-npn-server/pom.xml +++ b/jetty-npn/jetty-npn-server/pom.xml @@ -12,23 +12,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature with a snapshot. --> <plugin> diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index 7999c68ecdd..e6710d1d198 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -34,23 +34,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature with a snapshot. --> <plugin> diff --git a/jetty-proxy/pom.xml b/jetty-proxy/pom.xml index 36612da4d45..ebb99e7f45a 100644 --- a/jetty-proxy/pom.xml +++ b/jetty-proxy/pom.xml @@ -14,23 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-quickstart/pom.xml b/jetty-quickstart/pom.xml index 2e5e2b6cf36..87bad0d25e5 100644 --- a/jetty-quickstart/pom.xml +++ b/jetty-quickstart/pom.xml @@ -85,23 +85,6 @@ </dependencies> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> </project> diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index 99150972892..97e1c61d8f0 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -14,23 +14,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index 480e2ff2256..838749b24fc 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -32,23 +32,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index 0a200a105d7..6068b90d307 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -45,23 +45,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index 73bc85058ee..379ca786a21 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -45,23 +45,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index 98bfefdf14a..a8c2ee8b6a6 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -15,23 +15,6 @@ </properties> <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml index 148ff92242b..4708b9f4299 100644 --- a/jetty-spdy/spdy-http-server/pom.xml +++ b/jetty-spdy/spdy-http-server/pom.xml @@ -15,23 +15,6 @@ <build> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> diff --git a/jetty-spring/pom.xml b/jetty-spring/pom.xml index df362cb6d28..e5f1fbca73c 100644 --- a/jetty-spring/pom.xml +++ b/jetty-spring/pom.xml @@ -17,23 +17,6 @@ <build> <defaultGoal>install</defaultGoal> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> <dependencies> diff --git a/jetty-util-ajax/pom.xml b/jetty-util-ajax/pom.xml index ee95fe379d0..1e5c1ad4bbd 100644 --- a/jetty-util-ajax/pom.xml +++ b/jetty-util-ajax/pom.xml @@ -15,23 +15,6 @@ <build> <plugins> <!-- - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> --> <plugin> <groupId>org.codehaus.mojo</groupId> diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index c4f991b69b0..e5f2108ac86 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -31,23 +31,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index ffbc21d9e4a..095f204960a 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -27,23 +27,6 @@ </resource> </resources> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> diff --git a/jetty-websocket/javax-websocket-server-impl/pom.xml b/jetty-websocket/javax-websocket-server-impl/pom.xml index 745cac24834..56651501ca7 100644 --- a/jetty-websocket/javax-websocket-server-impl/pom.xml +++ b/jetty-websocket/javax-websocket-server-impl/pom.xml @@ -70,23 +70,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - <configuration> - <descriptorRefs> - <descriptorRef>config</descriptorRef> - </descriptorRefs> - </configuration> - </execution> - </executions> - </plugin> </plugins> </build> </project> diff --git a/pom.xml b/pom.xml index 62811d3a1fb..9ea077b639e 100644 --- a/pom.xml +++ b/pom.xml @@ -723,6 +723,36 @@ > mvn -N site:sshdeploy (for ssh users w/passphrase and ssh-agent) --> <profiles> + <profile> + <id>config</id> + <activation> + <file> + <exists>src/main/config</exists> + </file> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + <configuration> + <descriptorRefs> + <descriptorRef>config</descriptorRef> + </descriptorRefs> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> <id>eclipse-release</id> <modules> From 81ded3cdddd219ab7c4fd2d9a178f024071a7d5a Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 15 Aug 2014 16:57:37 +0200 Subject: [PATCH 239/269] Added JMX annotations to PushCacheFilter. --- .../jetty/servlets/PushCacheFilter.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java index bdeec795b59..bcfb135a0ec 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java @@ -20,6 +20,9 @@ package org.eclipse.jetty.servlets; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; @@ -40,6 +43,8 @@ import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.server.Dispatcher; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.URIUtil; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -54,6 +59,7 @@ import org.eclipse.jetty.util.log.Logger; * that indicates a possible push resource * </ul> */ +@ManagedObject("Push cache based on the HTTP 'Referer' header") public class PushCacheFilter implements Filter { private static final Logger LOG = Log.getLogger(PushCacheFilter.class); @@ -177,6 +183,19 @@ public class PushCacheFilter implements Filter _cache.clear(); } + @ManagedAttribute("The push cache contents") + public Map<String, String> getCache() + { + Map<String, String> result = new HashMap<>(); + for (Map.Entry<String, PrimaryResource> entry : _cache.entrySet()) + { + PrimaryResource resource = entry.getValue(); + String value = String.format("size=%d: %s", resource._associated.size(), new TreeSet<>(resource._associated.keySet())); + result.put(entry.getKey(), value); + } + return result; + } + private static class PrimaryResource { private final ConcurrentMap<String, RequestDispatcher> _associated = new ConcurrentHashMap<>(); From c7987b154a0c5719b05e4d6ea64a460a883f58fd Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 15 Aug 2014 17:29:38 +0200 Subject: [PATCH 240/269] Reverted logging of HTTP2 tests from DEBUG to INFO. --- .../http2-hpack/src/test/resources/jetty-logging.properties | 2 +- .../http2-server/src/test/resources/jetty-logging.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties index d33a7c32778..e40e8e43ce1 100644 --- a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties @@ -1,3 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog org.eclipse.jetty.http2.LEVEL=INFO -org.eclipse.jetty.http2.hpack.LEVEL=DEBUG +org.eclipse.jetty.http2.hpack.LEVEL=INFO diff --git a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties index c8c72f381ed..3d1e404e15a 100644 --- a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties @@ -1,3 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.http2.LEVEL=DEBUG +org.eclipse.jetty.http2.LEVEL=INFO From 75912deb52c69202c65a4f056bd0c64b0ddb3d13 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 15 Aug 2014 18:07:41 +0200 Subject: [PATCH 241/269] Updated parameter name from "associateDelay" to "associatePeriod". --- .../java/org/eclipse/jetty/servlets/PushCacheFilter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java index bcfb135a0ec..8555b08f58f 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java @@ -70,8 +70,9 @@ public class PushCacheFilter implements Filter @Override public void init(FilterConfig config) throws ServletException { - if (config.getInitParameter("associateDelay") != null) - _associatePeriod = Long.valueOf(config.getInitParameter("associateDelay")); + String associatePeriod = config.getInitParameter("associatePeriod"); + if (associatePeriod != null) + _associatePeriod = Long.valueOf(associatePeriod); } @Override From 728a7c3442c081e6b483ea347d813aa791e98d22 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Fri, 15 Aug 2014 18:34:20 +0200 Subject: [PATCH 242/269] Made push functionality honor configuration parameter sent via SETTINGS. --- .../org/eclipse/jetty/http2/HTTP2Session.java | 44 ++++++++++++++----- .../org/eclipse/jetty/http2/ISession.java | 2 + .../http2/server/HttpTransportOverHTTP2.java | 7 +++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 01e768b741f..a400370c9c9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -81,6 +81,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final HTTP2Flusher flusher; private int maxLocalStreams; private int maxRemoteStreams; + private boolean pushEnabled; public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int maxStreams, int initialStreamId) { @@ -95,6 +96,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener this.streamIds.set(initialStreamId); this.sendWindow.set(FlowControl.DEFAULT_WINDOW_SIZE); this.recvWindow.set(FlowControl.DEFAULT_WINDOW_SIZE); + this.pushEnabled = true; // SPEC: by default, push is enabled. } public FlowControl getFlowControl() @@ -200,31 +202,44 @@ public abstract class HTTP2Session implements ISession, Parser.Listener // Iterate over all settings for (Map.Entry<Integer, Integer> entry : frame.getSettings().entrySet()) { - int value=entry.getValue(); - switch (entry.getKey()) + int key = entry.getKey(); + int value = entry.getValue(); + switch (key) { case SettingsFrame.HEADER_TABLE_SIZE: + { if (LOG.isDebugEnabled()) LOG.debug("Update HPACK header table size to {}", value); generator.setHeaderTableSize(value); break; - + } case SettingsFrame.ENABLE_PUSH: + { + // SPEC: check the value is sane. + if (value != 0 && value != 1) + { + onConnectionFailure(ErrorCodes.PROTOCOL_ERROR, "invalid_settings_enable_push"); + return false; + } + pushEnabled = value == 1; break; - + } case SettingsFrame.MAX_CONCURRENT_STREAMS: + { maxLocalStreams = value; if (LOG.isDebugEnabled()) LOG.debug("Update max local concurrent streams to {}", maxLocalStreams); break; - + } case SettingsFrame.INITIAL_WINDOW_SIZE: + { if (LOG.isDebugEnabled()) LOG.debug("Update initial window size to {}", value); flowControl.updateInitialStreamWindow(this, value); break; - + } case SettingsFrame.MAX_FRAME_SIZE: + { if (LOG.isDebugEnabled()) LOG.debug("Update max frame size to {}", value); // SPEC: check the max frame size is sane. @@ -234,16 +249,19 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return false; } generator.setMaxFrameSize(value); - break; - + } case SettingsFrame.MAX_HEADER_LIST_SIZE: + { // TODO implement LOG.warn("NOT IMPLEMENTED max header list size to {}", value); break; - + } default: - LOG.debug("Unknown setting {}:{}",entry.getKey(),value); + { + LOG.debug("Unknown setting {}:{}", key, value); + break; + } } } notifySettings(this, frame); @@ -568,6 +586,12 @@ public abstract class HTTP2Session implements ISession, Parser.Listener flusher.window(stream, frame); } + @Override + public boolean isPushEnabled() + { + return pushEnabled; + } + @Override public void shutdown() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index 024922ce509..c891abed16b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -44,6 +44,8 @@ public interface ISession extends Session public void onWindowUpdate(IStream stream, WindowUpdateFrame frame); + public boolean isPushEnabled(); + public void shutdown(); public void disconnect(); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index b0e5b48826c..24bb38cd1a2 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -100,6 +100,13 @@ public class HttpTransportOverHTTP2 implements HttpTransport @Override public void push(final MetaData.Request request) { + if (!stream.getSession().isPushEnabled()) + { + if (LOG.isDebugEnabled()) + LOG.debug("HTTP/2 Push disabled for {}", request); + return; + } + stream.push(new PushPromiseFrame(stream.getId(), 0, request), new Promise<Stream>() { @Override From 09d54eacabfdae5499564a20c451b4162442ccfc Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 19 Aug 2014 13:38:43 +0200 Subject: [PATCH 243/269] Accounting for the session flow control window in case of reset streams. --- .../java/org/eclipse/jetty/http2/FlowControl.java | 2 +- .../org/eclipse/jetty/http2/HTTP2FlowControl.java | 12 +++++++----- .../java/org/eclipse/jetty/http2/HTTP2Session.java | 11 +++++++---- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java index 1126f74b324..e87aa3d8533 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControl.java @@ -30,7 +30,7 @@ public interface FlowControl public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame); - public void onDataReceived(IStream stream, int length); + public void onDataReceived(ISession session, IStream stream, int length); public void onDataConsumed(IStream stream, int length); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java index dd426fb876b..937fe1e2059 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2FlowControl.java @@ -78,16 +78,18 @@ public class HTTP2FlowControl implements FlowControl } @Override - public void onDataReceived(IStream stream, int length) + public void onDataReceived(ISession session, IStream stream, int length) { - ISession session = stream.getSession(); int oldSize = session.updateRecvWindow(-length); if (LOG.isDebugEnabled()) LOG.debug("Updated session recv window {} -> {} for {}", oldSize, oldSize - length, session); - oldSize = stream.updateRecvWindow(-length); - if (LOG.isDebugEnabled()) - LOG.debug("Updated stream recv window {} -> {} for {}", oldSize, oldSize - length, stream); + if (stream != null) + { + oldSize = stream.updateRecvWindow(-length); + if (LOG.isDebugEnabled()) + LOG.debug("Updated stream recv window {} -> {} for {}", oldSize, oldSize - length, stream); + } } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index a400370c9c9..5e510372a39 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -129,16 +129,19 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { if (LOG.isDebugEnabled()) LOG.debug("Received {}", frame); + int streamId = frame.getStreamId(); final IStream stream = getStream(streamId); + + // SPEC: the session window must be updated even if the stream is null. + // The flow control length includes the padding bytes. + final int flowControlLength = frame.remaining() + frame.padding(); + flowControl.onDataReceived(this, stream, flowControlLength); + if (stream != null) { stream.updateClose(frame.isEndStream(), false); - // The flow control length includes the padding bytes. - final int flowControlLength = frame.remaining() + frame.padding(); - flowControl.onDataReceived(stream, flowControlLength); - if (getRecvWindow() < 0) { close(ErrorCodes.FLOW_CONTROL_ERROR, "session_window_exceeded", disconnectOnFailure); From 20076fcdc517c428f331f83490f435f2219465c5 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 19 Aug 2014 13:41:52 +0200 Subject: [PATCH 244/269] Moved reset() from Session to Stream. --- .../org/eclipse/jetty/http2/client/StreamResetTest.java | 6 +++--- .../main/java/org/eclipse/jetty/http2/HTTP2Session.java | 3 +-- .../main/java/org/eclipse/jetty/http2/HTTP2Stream.java | 8 +++++++- .../main/java/org/eclipse/jetty/http2/api/Session.java | 2 -- .../src/main/java/org/eclipse/jetty/http2/api/Stream.java | 3 +++ 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java index 8d14943322d..8e8ce403b66 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java @@ -54,7 +54,7 @@ public class StreamResetTest extends AbstractTest Stream stream = promise.get(5, TimeUnit.SECONDS); ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCodes.CANCEL_STREAM_ERROR); FutureCallback resetCallback = new FutureCallback(); - stream.getSession().reset(resetFrame, resetCallback); + stream.reset(resetFrame, resetCallback); resetCallback.get(5, TimeUnit.SECONDS); // After reset the stream should be gone. Assert.assertEquals(0, client.getStreams().size()); @@ -85,7 +85,7 @@ public class StreamResetTest extends AbstractTest client.newStream(requestFrame, promise, new Stream.Listener.Adapter()); Stream stream = promise.get(5, TimeUnit.SECONDS); ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCodes.CANCEL_STREAM_ERROR); - stream.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); + stream.reset(resetFrame, Callback.Adapter.INSTANCE); Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); Stream serverStream = streamRef.get(); @@ -171,7 +171,7 @@ public class StreamResetTest extends AbstractTest Stream stream2 = promise2.get(5, TimeUnit.SECONDS); ResetFrame resetFrame = new ResetFrame(stream1.getId(), ErrorCodes.CANCEL_STREAM_ERROR); - stream1.getSession().reset(resetFrame, Callback.Adapter.INSTANCE); + stream1.reset(resetFrame, Callback.Adapter.INSTANCE); Assert.assertTrue(serverResetLatch.await(5, TimeUnit.SECONDS)); // Stream MUST NOT receive data sent by server after reset. diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 5e510372a39..fe3452b4b74 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -396,8 +396,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener control(null, callback, frame); } - @Override - public void reset(ResetFrame frame, Callback callback) + protected void reset(ResetFrame frame, Callback callback) { control(getStream(frame.getStreamId()), callback, frame); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index f22a93c915f..dc19e878072 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -95,6 +95,12 @@ public class HTTP2Stream extends IdleTimeout implements IStream session.data(this, callback, frame); } + @Override + public void reset(ResetFrame frame, Callback callback) + { + session.control(this, callback, frame, Frame.EMPTY_ARRAY); + } + @Override public Object getAttribute(String key) { @@ -141,7 +147,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream // avoid that its idle timeout is rescheduled. close(); - session.reset(new ResetFrame(getId(), ErrorCodes.CANCEL_STREAM_ERROR), disconnectOnFailure); + reset(new ResetFrame(getId(), ErrorCodes.CANCEL_STREAM_ERROR), disconnectOnFailure); notifyFailure(this, timeout); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java index 3249a4d60bf..e9df4786657 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java @@ -37,8 +37,6 @@ public interface Session public void ping(PingFrame frame, Callback callback); - public void reset(ResetFrame frame, Callback callback); - public void close(int error, String payload, Callback callback); public Collection<Stream> getStreams(); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index c5aa7f2bed2..f9287272c4f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.api; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; @@ -36,6 +37,8 @@ public interface Stream public void data(DataFrame frame, Callback callback); + public void reset(ResetFrame frame, Callback callback); + public Object getAttribute(String key); public void setAttribute(String key, Object value); From d4f140ff65dd80fb34ebc86f5546fc2b2248414d Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 19 Aug 2014 13:43:24 +0200 Subject: [PATCH 245/269] Ignoring HEADERS, PUSH_PROMISE and DATA if the stream cannot be found. This typically happens when the stream has been reset. --- .../eclipse/jetty/http2/client/HTTP2ClientSession.java | 10 ++++------ .../java/org/eclipse/jetty/http2/HTTP2Session.java | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index 7a47f81cbca..6d547e4bda9 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -18,14 +18,12 @@ package org.eclipse.jetty.http2.client; -import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.FlowControl; import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; -import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; @@ -52,8 +50,8 @@ public class HTTP2ClientSession extends HTTP2Session IStream stream = getStream(streamId); if (stream == null) { - ResetFrame reset = new ResetFrame(streamId, ErrorCodes.STREAM_CLOSED_ERROR); - reset(reset, disconnectOnFailure()); + if (LOG.isDebugEnabled()) + LOG.debug("Ignoring {}, stream #{} not found", frame, streamId); } else { @@ -92,8 +90,8 @@ public class HTTP2ClientSession extends HTTP2Session IStream stream = getStream(streamId); if (stream == null) { - ResetFrame reset = new ResetFrame(pushStreamId, ErrorCodes.STREAM_CLOSED_ERROR); - reset(reset, disconnectOnFailure()); + if (LOG.isDebugEnabled()) + LOG.debug("Ignoring {}, stream #{} not found", frame, streamId); } else { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index fe3452b4b74..81a7bb00886 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -163,8 +163,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } else { - ResetFrame resetFrame = new ResetFrame(streamId, ErrorCodes.STREAM_CLOSED_ERROR); - reset(resetFrame, disconnectOnFailure()); + if (LOG.isDebugEnabled()) + LOG.debug("Ignoring {}, stream #{} not found", frame, streamId); return false; } } From 8e62a50500df748be235101fb0a301658027b25f Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 19 Aug 2014 18:37:53 +0200 Subject: [PATCH 246/269] 442086 - Review HttpOutput blocking writes. Reviewed blocking writes call sites and handled exceptions in the same way for all of them, calling HttpChannel.abort(Throwable). Modified HttpChannel.abort() to take the failure as parameter, so that subclasses may inspect the failure and decide what to do. --- .../fcgi/server/HttpTransportOverFCGI.java | 2 +- .../org/eclipse/jetty/server/HttpChannel.java | 24 ++-- .../jetty/server/HttpChannelOverHttp.java | 6 +- .../eclipse/jetty/server/HttpConnection.java | 2 +- .../org/eclipse/jetty/server/HttpOutput.java | 116 +++++++++++------- .../eclipse/jetty/server/HttpTransport.java | 18 ++- .../org/eclipse/jetty/server/Response.java | 9 +- .../eclipse/jetty/server/ResponseTest.java | 18 ++- .../server/http/HttpTransportOverSPDY.java | 2 +- 9 files changed, 118 insertions(+), 79 deletions(-) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java index 786f505c258..5e0b7e6d813 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java @@ -129,7 +129,7 @@ public class HttpTransportOverFCGI implements HttpTransport } @Override - public void abort() + public void abort(Throwable failure) { aborted = true; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 8932bd9742e..0ce0a5be660 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -25,7 +25,6 @@ import java.nio.channels.ClosedChannelException; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; @@ -45,7 +44,6 @@ import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.server.HttpChannelState.Action; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ErrorHandler; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.SharedBlockingCallback.Blocker; import org.eclipse.jetty.util.log.Log; @@ -411,7 +409,7 @@ public class HttpChannel implements Runnable } else if (isCommitted()) { - _transport.abort(); + _transport.abort(x); if (!(x instanceof EofException)) LOG.warn("Could not send response error 500: "+x); } @@ -551,6 +549,13 @@ public class HttpChannel implements Runnable blocker.block(); return committing; } + catch (Throwable failure) + { + if (LOG.isDebugEnabled()) + LOG.debug(failure); + abort(failure); + throw failure; + } } public boolean isCommitted() @@ -580,7 +585,6 @@ public class HttpChannel implements Runnable return _connector.getScheduler(); } - /* ------------------------------------------------------------ */ /** * @return true if the HttpChannel can efficiently use direct buffer (typically this means it is not over SSL or a multiplexed protocol) */ @@ -590,12 +594,16 @@ public class HttpChannel implements Runnable } /** - * If a write or similar to this channel fails this method should be called. The standard implementation - * is to call {@link HttpTransport#abort()} + * If a write or similar operation to this channel fails, + * then this method should be called. + * <p /> + * The standard implementation calls {@link HttpTransport#abort(Throwable)}. + * + * @param failure the failure that caused the abort. */ - public void abort() + public void abort(Throwable failure) { - _transport.abort(); + _transport.abort(failure); } private class CommitCallback implements Callback diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 625213050eb..968d95f223e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -31,13 +31,11 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; -import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.EndPoint; -import org.omg.stub.java.rmi._Remote_Stub; /** * A HttpChannel customized to be transported over the HTTP/1 protocol @@ -304,9 +302,9 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl } @Override - public void abort() + public void abort(Throwable failure) { - super.abort(); + super.abort(failure); _httpConnection._generator.setPersistent(false); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 61fb63d392c..39ee045cfd0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -628,7 +628,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http } @Override - public void abort() + public void abort(Throwable failure) { // Do a direct close of the output, as this may indicate to a client that the // response is bad either with RST or by abnormal completion of chunked response. diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index fc5d6706f23..123767ea388 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -24,7 +24,10 @@ import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritePendingException; import java.util.concurrent.atomic.AtomicReference; +import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import javax.servlet.WriteListener; import org.eclipse.jetty.http.HttpContent; @@ -119,11 +122,18 @@ public class HttpOutput extends ServletOutputStream implements Runnable protected void write(ByteBuffer content, boolean complete) throws IOException { - try (Blocker blocker=_writeblock.acquire()) + try (Blocker blocker = _writeblock.acquire()) { - write(content,complete,blocker); + write(content, complete, blocker); blocker.block(); } + catch (Throwable failure) + { + if (LOG.isDebugEnabled()) + LOG.debug(failure); + _channel.abort(failure); + throw failure; + } } protected void write(ByteBuffer content, boolean complete, Callback callback) @@ -140,28 +150,34 @@ public class HttpOutput extends ServletOutputStream implements Runnable switch (state) { case CLOSED: + { break loop; - + } case UNREADY: + { if (_state.compareAndSet(state,OutputState.ERROR)) _writeListener.onError(_onError==null?new EofException("Async close"):_onError); continue; - + } default: + { if (_state.compareAndSet(state,OutputState.CLOSED)) { try { - write(BufferUtil.hasContent(_aggregate)?_aggregate:BufferUtil.EMPTY_BUFFER,!_channel.getResponse().isIncluding()); + write(BufferUtil.hasContent(_aggregate)?_aggregate:BufferUtil.EMPTY_BUFFER, !_channel.getResponse().isIncluding()); + break loop; } - catch(IOException e) + catch (IOException x) { - LOG.debug(e); - _channel.abort(); + // Ignore it, it's been already logged in write(). + } + finally + { + releaseBuffer(); } - releaseBuffer(); - return; } + } } } } @@ -189,10 +205,10 @@ public class HttpOutput extends ServletOutputStream implements Runnable { _channel.getResponse().closeOutput(); } - catch(IOException e) + catch(Throwable e) { LOG.debug(e); - _channel.abort(); + _channel.abort(e); } releaseBuffer(); return; @@ -367,11 +383,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable write(view,complete); } else if (complete) - write(BufferUtil.EMPTY_BUFFER,complete); + { + write(BufferUtil.EMPTY_BUFFER,true); + } if (complete) closed(); - } public void write(ByteBuffer buffer) throws IOException @@ -424,7 +441,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable if (len>0) write(buffer, complete); else if (complete) - write(BufferUtil.EMPTY_BUFFER,complete); + write(BufferUtil.EMPTY_BUFFER, true); if (complete) closed(); @@ -449,11 +466,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable // Check if all written or full if (complete || BufferUtil.isFull(_aggregate)) { - try(Blocker blocker=_writeblock.acquire()) - { - write(_aggregate, complete, blocker); - blocker.block(); - } + write(_aggregate, complete); if (complete) closed(); } @@ -512,11 +525,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable */ public void sendContent(ByteBuffer content) throws IOException { - try(Blocker blocker=_writeblock.acquire()) - { - write(content,true,blocker); - blocker.block(); - } + write(content, true); } /* ------------------------------------------------------------ */ @@ -528,9 +537,16 @@ public class HttpOutput extends ServletOutputStream implements Runnable { try(Blocker blocker=_writeblock.acquire()) { - new InputStreamWritingCB(in,blocker).iterate(); + new InputStreamWritingCB(in, blocker).iterate(); blocker.block(); } + catch (Throwable failure) + { + if (LOG.isDebugEnabled()) + LOG.debug(failure); + _channel.abort(failure); + throw failure; + } } /* ------------------------------------------------------------ */ @@ -542,9 +558,16 @@ public class HttpOutput extends ServletOutputStream implements Runnable { try(Blocker blocker=_writeblock.acquire()) { - new ReadableByteChannelWritingCB(in,blocker).iterate(); + new ReadableByteChannelWritingCB(in, blocker).iterate(); blocker.block(); } + catch (Throwable failure) + { + if (LOG.isDebugEnabled()) + LOG.debug(failure); + _channel.abort(failure); + throw failure; + } } @@ -557,9 +580,16 @@ public class HttpOutput extends ServletOutputStream implements Runnable { try(Blocker blocker=_writeblock.acquire()) { - sendContent(content,blocker); + sendContent(content, blocker); blocker.block(); } + catch (Throwable failure) + { + if (LOG.isDebugEnabled()) + LOG.debug(failure); + _channel.abort(failure); + throw failure; + } } /* ------------------------------------------------------------ */ @@ -569,7 +599,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable */ public void sendContent(ByteBuffer content, final Callback callback) { - write(content,true,new Callback() + write(content, true, new Callback() { @Override public void succeeded() @@ -594,7 +624,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable */ public void sendContent(InputStream in, Callback callback) { - new InputStreamWritingCB(in,callback).iterate(); + new InputStreamWritingCB(in, callback).iterate(); } /* ------------------------------------------------------------ */ @@ -605,7 +635,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable */ public void sendContent(ReadableByteChannel in, Callback callback) { - new ReadableByteChannelWritingCB(in,callback).iterate(); + new ReadableByteChannelWritingCB(in, callback).iterate(); } /* ------------------------------------------------------------ */ @@ -751,10 +781,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable { case CLOSED: case ERROR: + { _onError=null; break loop; - + } default: + { if (_state.compareAndSet(state, OutputState.ERROR)) { Throwable th=_onError; @@ -763,10 +795,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable LOG.debug("onError",th); _writeListener.onError(th); close(); - break loop; } - + } } continue; } @@ -775,6 +806,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable { case READY: case CLOSED: + { // even though a write is not possible, because a close has // occurred, we need to call onWritePossible to tell async // producer that the last write completed. @@ -785,11 +817,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable } catch (Throwable e) { - _onError=e; + _onError = e; } break; + } default: - + { + break; + } } } } @@ -838,8 +873,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable _channel.getState().onWritePossible(); } } - - + private class AsyncFlush extends AsyncICB { protected volatile boolean _flushed; @@ -869,8 +903,6 @@ public class HttpOutput extends ServletOutputStream implements Runnable } } - - private class AsyncWrite extends AsyncICB { private final ByteBuffer _buffer; @@ -959,11 +991,8 @@ public class HttpOutput extends ServletOutputStream implements Runnable if (_complete) closed(); } - - } - /* ------------------------------------------------------------ */ /** An iterating callback that will take content from an * InputStream and write it to the associated {@link HttpChannel}. @@ -1031,7 +1060,6 @@ public class HttpOutput extends ServletOutputStream implements Runnable LOG.ignore(e); } } - } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java index 975c80a67c5..f9607450ad6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java @@ -32,10 +32,18 @@ public interface HttpTransport void completed(); - /* ------------------------------------------------------------ */ - /** Abort transport. - * This is called when an error response needs to be sent, but the response is already committed. - * Abort to should terminate the transport in a way that can indicate abnormal response to the client. + /** + * Aborts this transport. + * <p /> + * This method should terminate the transport in a way that + * can indicate an abnormal response to the client, for example + * by abruptly close the connection. + * <p /> + * This method is called when an error response needs to be sent, + * but the response is already committed, or when a write failure + * is detected. + * + * @param failure the failure that caused the abort. */ - void abort(); + void abort(Throwable failure); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index d8b30d246e3..4b06ff1e423 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -18,8 +18,6 @@ package org.eclipse.jetty.server; -import static org.eclipse.jetty.util.QuotedStringTokenizer.isQuoted; - import java.io.IOException; import java.io.PrintWriter; import java.nio.channels.IllegalSelectorException; @@ -30,7 +28,6 @@ import java.util.Enumeration; import java.util.Iterator; import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; @@ -300,7 +297,9 @@ public class Response implements HttpServletResponse boolean quote_path = has_path && isQuoteNeededForCookie(path); // Upgrade the version if we have a comment or we need to quote value/path/domain or if they were already quoted - if (version==0 && ( comment!=null || quote_name || quote_value || quote_domain || quote_path || isQuoted(name) || isQuoted(value) || isQuoted(path) || isQuoted(domain))) + if (version==0 && ( comment!=null || quote_name || quote_value || quote_domain || quote_path || + QuotedStringTokenizer.isQuoted(name) || QuotedStringTokenizer.isQuoted(value) || + QuotedStringTokenizer.isQuoted(path) || QuotedStringTokenizer.isQuoted(domain))) version=1; // Append version @@ -557,7 +556,7 @@ public class Response implements HttpServletResponse switch(code) { case -1: - _channel.abort(); + _channel.abort(new IOException()); return; case 102: sendProcessing(); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 2bc866863f5..cb62b25cd3e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -18,13 +18,6 @@ package org.eclipse.jetty.server; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - import java.io.IOException; import java.io.InputStreamReader; import java.io.LineNumberReader; @@ -36,7 +29,6 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.Locale; - import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; @@ -65,6 +57,13 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + public class ResponseTest { private Server _server; @@ -102,9 +101,8 @@ public class ResponseTest } @Override - public void abort() + public void abort(Throwable failure) { - } }, input); diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java index 682d7541aed..c85e04a30ac 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java @@ -419,7 +419,7 @@ public class HttpTransportOverSPDY implements HttpTransport } @Override - public void abort() + public void abort(Throwable failure) { // TODO close the stream in a way to indicate an incomplete response? } From c15480644fc191adb1360150b7dbc3a0a79c7fc7 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Tue, 19 Aug 2014 18:40:01 +0200 Subject: [PATCH 247/269] 442083 - Client resets stream, pending server data is failed, connection closed. Introduced ResetException, and using it when failing frames of streams that have been reset already. HttpTransportOverHTTP2.abort(Throwable) checks for this exception and does not close the connection. --- .../eclipse/jetty/http2/client/PushTest.java | 111 +++++++++++++++++- .../org/eclipse/jetty/http2/HTTP2Flusher.java | 3 +- .../eclipse/jetty/http2/ResetException.java | 46 ++++++++ .../http2/server/HttpTransportOverHTTP2.java | 6 +- 4 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ResetException.java diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java index 4f622816d07..e2bb219be56 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java @@ -32,11 +32,13 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlets.PushCacheFilter; import org.eclipse.jetty.util.Callback; @@ -78,7 +80,7 @@ public class PushTest extends AbstractTest final String primaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource; HttpFields primaryFields = new HttpFields(); MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields); - final CountDownLatch secondaryResponseLatch = new CountDownLatch(1); + final CountDownLatch warmupLatch = new CountDownLatch(1); session.newStream(new HeadersFrame(0, primaryRequest, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() { @Override @@ -96,13 +98,13 @@ public class PushTest extends AbstractTest @Override public void onData(Stream stream, DataFrame frame, Callback callback) { - secondaryResponseLatch.countDown(); + warmupLatch.countDown(); } }); } } }); - Assert.assertTrue(secondaryResponseLatch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS)); // Request again the primary resource, we should get the secondary resource pushed. primaryRequest = newRequest("GET", primaryResource, primaryFields); @@ -136,4 +138,107 @@ public class PushTest extends AbstractTest Assert.assertTrue(pushLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS)); } + + @Test + public void testPushIsReset() throws Exception + { + final String primaryResource = "/primary.html"; + final String secondaryResource = "/secondary.png"; + final byte[] secondaryData = "SECONDARY".getBytes("UTF-8"); + startServer(new HttpServlet() + { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + String requestURI = req.getRequestURI(); + ServletOutputStream output = resp.getOutputStream(); + if (requestURI.endsWith(primaryResource)) + output.print("<html><head></head><body>PRIMARY</body></html>"); + else if (requestURI.endsWith(secondaryResource)) + output.write(secondaryData); + } + }); + + final Session session = newClient(new Session.Listener.Adapter()); + + // Request for the primary and secondary resource to build the cache. + final String primaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource; + HttpFields primaryFields = new HttpFields(); + MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields); + final CountDownLatch warmupLatch = new CountDownLatch(1); + session.newStream(new HeadersFrame(0, primaryRequest, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + { + // Request for the secondary resource. + HttpFields secondaryFields = new HttpFields(); + secondaryFields.put(HttpHeader.REFERER, primaryURI); + MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields); + session.newStream(new HeadersFrame(0, secondaryRequest, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + warmupLatch.countDown(); + } + }); + } + } + }); + Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS)); + + // Request again the primary resource, we should get the secondary resource pushed. + primaryRequest = newRequest("GET", primaryResource, primaryFields); + final CountDownLatch primaryResponseLatch = new CountDownLatch(1); + final CountDownLatch pushLatch = new CountDownLatch(1); + session.newStream(new HeadersFrame(0, primaryRequest, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public Stream.Listener onPush(Stream stream, PushPromiseFrame frame) + { + // Reset the stream as soon as we see the push. + ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCodes.REFUSED_STREAM_ERROR); + stream.reset(resetFrame, Callback.Adapter.INSTANCE); + return new Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + pushLatch.countDown(); + } + }; + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + callback.succeeded(); + if (frame.isEndStream()) + primaryResponseLatch.countDown(); + } + }); + // We should not receive pushed data that we reset. + Assert.assertFalse(pushLatch.await(1, TimeUnit.SECONDS)); + Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS)); + + // Make sure the session is sane by requesting the secondary resource. + HttpFields secondaryFields = new HttpFields(); + secondaryFields.put(HttpHeader.REFERER, primaryURI); + MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields); + final CountDownLatch secondaryResponseLatch = new CountDownLatch(1); + session.newStream(new HeadersFrame(0, secondaryRequest, null, true), new Promise.Adapter<Stream>(), new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + if (frame.isEndStream()) + secondaryResponseLatch.countDown(); + } + }); + Assert.assertTrue(secondaryResponseLatch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java index ec58db8c39d..22979de5295 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.http2; -import java.io.EOFException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.ArrayDeque; @@ -348,7 +347,7 @@ public class HTTP2Flusher extends IteratingCallback public void reset() { - failed(new EOFException("reset")); + failed(new ResetException()); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ResetException.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ResetException.java new file mode 100644 index 00000000000..8bdf23a19d8 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ResetException.java @@ -0,0 +1,46 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2; + +public class ResetException extends RuntimeException +{ + public ResetException() + { + } + + public ResetException(String message) + { + super(message); + } + + public ResetException(String message, Throwable cause) + { + super(message, cause); + } + + public ResetException(Throwable cause) + { + super(cause); + } + + public ResetException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) + { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 24bb38cd1a2..05c66b0ac10 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.IStream; +import org.eclipse.jetty.http2.ResetException; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -162,11 +163,12 @@ public class HttpTransportOverHTTP2 implements HttpTransport } @Override - public void abort() + public void abort(Throwable failure) { if (LOG.isDebugEnabled()) LOG.debug("HTTP2 Response #{} aborted", stream.getId()); - stream.getSession().disconnect(); + if (!(failure instanceof ResetException)) + stream.getSession().disconnect(); } private class CommitCallback implements Callback From 7700d1ce536443a2398618eaf143ce1939e7e1fe Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt <joakim.erdfelt@gmail.com> Date: Tue, 19 Aug 2014 10:33:04 -0700 Subject: [PATCH 248/269] Testcase is sensitive to System Property from other tests. + Making the testcase for PathFinderTest not discover jetty.base, as this value can be obtained from System Property (set from another test case) giving false success/failure based on run order. --- .../org/eclipse/jetty/start/BaseHome.java | 1 - .../org/eclipse/jetty/start/ModulesTest.java | 44 +++++++++++++++++++ .../eclipse/jetty/start/PathFinderTest.java | 13 +++++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java index 6921df6816d..c7fc17d3b00 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java @@ -130,7 +130,6 @@ public class BaseHome public BaseHome(CommandLineConfigSource cmdLineSource) throws IOException { - sources = new ConfigSources(); sources.add(cmdLineSource); this.homeDir = cmdLineSource.getHomePath(); diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java index 506ad932ce0..5806df23764 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java @@ -116,6 +116,50 @@ public class ModulesTest ConfigurationAssert.assertContainsUnordered("All Modules",expected,moduleNames); } + + /** + * Test loading of only shallow modules, not deep references. + * In other words. ${search-dir}/modules/*.mod should be the only + * valid references, but ${search-dir}/alt/foo/modules/*.mod should + * not be considered valid. + */ + @Test + public void testLoadShallowModulesOnly() throws IOException + { + // Test Env + File homeDir = MavenTestingUtils.getTestResourceDir("jetty home with spaces"); + // intentionally setup top level resources dir (as this would have many deep references) + File baseDir = MavenTestingUtils.getTestResourcesDir(); + String cmdLine[] = new String[] {"jetty.version=TEST"}; + + // Configuration + CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine); + ConfigSources config = new ConfigSources(); + config.add(cmdLineSource); + config.add(new JettyHomeConfigSource(homeDir.toPath())); + config.add(new JettyBaseConfigSource(baseDir.toPath())); + + // Initialize + BaseHome basehome = new BaseHome(config); + + StartArgs args = new StartArgs(); + args.parse(config); + + // Test Modules + Modules modules = new Modules(basehome,args); + modules.registerAll(); + + List<String> moduleNames = new ArrayList<>(); + for (Module mod : modules) + { + moduleNames.add(mod.getName()); + } + + List<String> expected = new ArrayList<>(); + expected.add("base"); + + ConfigurationAssert.assertContainsUnordered("All Modules",expected,moduleNames); + } @Test public void testEnableRegexSimple() throws IOException diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java index 18b05cd7bd4..978dc9e4736 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java @@ -28,15 +28,22 @@ import java.util.EnumSet; import java.util.List; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestingDir; +import org.junit.Rule; import org.junit.Test; public class PathFinderTest { + @Rule + public TestingDir testdir = new TestingDir(); + @Test public void testFindInis() throws IOException { File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home"); Path homePath = homeDir.toPath().toAbsolutePath(); + File baseDir = testdir.getEmptyDir(); + Path basePath = baseDir.toPath().toAbsolutePath(); PathFinder finder = new PathFinder(); finder.setFileMatcher("glob:**/*.ini"); @@ -53,7 +60,7 @@ public class PathFinderTest expected.add("${jetty.home}/start.ini"); FSTest.toOsSeparators(expected); - BaseHome hb = new BaseHome(new String[] { "jetty.home=" + homePath.toString() }); + BaseHome hb = new BaseHome(new String[] { "jetty.home=" + homePath.toString(), "jetty.base=" + basePath.toString() }); BaseHomeTest.assertPathList(hb,"Files found",expected,finder); } @@ -62,6 +69,8 @@ public class PathFinderTest { File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home"); Path homePath = homeDir.toPath().toAbsolutePath(); + File baseDir = testdir.getEmptyDir(); + Path basePath = baseDir.toPath().toAbsolutePath(); List<String> expected = new ArrayList<>(); File modulesDir = new File(homeDir,"modules"); @@ -82,7 +91,7 @@ public class PathFinderTest Files.walkFileTree(modulesPath,EnumSet.of(FileVisitOption.FOLLOW_LINKS),1,finder); - BaseHome hb = new BaseHome(new String[] { "jetty.home=" + homePath.toString() }); + BaseHome hb = new BaseHome(new String[] { "jetty.home=" + homePath.toString(), "jetty.base=" + basePath.toString() }); BaseHomeTest.assertPathList(hb,"Files found",expected,finder); } } From 9b36f999d1830941c5620a5dcd062b7e5e9b0ad3 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 20 Aug 2014 12:22:16 +1000 Subject: [PATCH 249/269] fixed merge --- .../src/main/java/org/eclipse/jetty/server/HttpChannel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 0187179ca7b..49a5817f275 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -315,7 +315,7 @@ public class HttpChannel implements Runnable else { error=true; - LOG.warn(String.valueOf(_uri), e); + LOG.warn(String.valueOf(_request.getHttpURI()), e); _state.error(e); _request.setHandled(true); handleException(e); From 984c7fdd85f152e231ce39c44c540b42ed8796c1 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 20 Aug 2014 17:54:01 +1000 Subject: [PATCH 250/269] various updates --- .../java/org/eclipse/jetty/server/Dispatcher.java | 9 +++++++++ .../java/org/eclipse/jetty/server/Response.java | 7 +++++++ pom.xml | 13 +++++++++++++ 3 files changed, 29 insertions(+) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java index cd19dedd724..4a50fa09cef 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; + import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; @@ -32,6 +33,7 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.server.handler.ContextHandler; @@ -228,6 +230,13 @@ public class Dispatcher implements RequestDispatcher else query=query+"&"+_uri.getQuery(); // TODO is this correct semantic? } + + int port=request.getServerPort(); + if (port==80 && HttpScheme.HTTP.is(request.getScheme())) + port=0; + if (port==443 && HttpScheme.HTTPS.is(request.getScheme())) + port=0; + HttpURI uri = new HttpURI(request.getScheme(),request.getServerName(),request.getServerPort(),_uri.getPath(),baseRequest.getHttpURI().getParam(),query,null); MetaData.Request push = new MetaData.Request(HttpMethod.GET.asString(),uri,baseRequest.getHttpVersion(),fields); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 4b06ff1e423..93f283e60bb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -553,6 +553,13 @@ public class Response implements HttpServletResponse if (isIncluding()) return; + if (isCommitted()) + { + if (LOG.isDebugEnabled()) + LOG.debug("Aborting on sendError on committed response {} {}",code,message); + code=-1; + } + switch(code) { case -1: diff --git a/pom.xml b/pom.xml index 9ea077b639e..3a876fb805e 100644 --- a/pom.xml +++ b/pom.xml @@ -965,6 +965,19 @@ <alpn.version>7.0.0.v20140317</alpn.version> </properties> </profile> + <profile> + <id>7u67</id> + <activation> + <property> + <name>java.version</name> + <value>1.7.0_67</value> + </property> + </activation> + <properties> + <npn.version>1.1.7.v20140316</npn.version> + <alpn.version>7.0.0.v20140317</alpn.version> + </properties> + </profile> <profile> <id>8u00</id> <activation> From abcce1140e6ea4093131559408fda15112a71485 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 21 Aug 2014 17:13:18 +1000 Subject: [PATCH 251/269] alpn-1.7.0_67 --- .../main/config/modules/protonego-impl/alpn-1.7.0_67.mod | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_67.mod diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_67.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_67.mod new file mode 100644 index 00000000000..45bbad75c9f --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_67.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar From c10e5e8833858aacae6551ce417a7d3c5248f770 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 20 Aug 2014 18:39:58 +0200 Subject: [PATCH 252/269] Renamed PushTest -> PushCacheFilterTest. --- .../http2/client/{PushTest.java => PushCacheFilterTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/{PushTest.java => PushCacheFilterTest.java} (99%) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java similarity index 99% rename from jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java rename to jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java index e2bb219be56..a03b742de85 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java @@ -46,7 +46,7 @@ import org.eclipse.jetty.util.Promise; import org.junit.Assert; import org.junit.Test; -public class PushTest extends AbstractTest +public class PushCacheFilterTest extends AbstractTest { @Override protected void customizeContext(ServletContextHandler context) From 7a61c96ba188e4f7664f94cf15d93a9d5b09920f Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 20 Aug 2014 18:44:13 +0200 Subject: [PATCH 253/269] Removed debug logging (wrongly assumes the ByteBuffer has a backing array). --- .../main/java/org/eclipse/jetty/http2/parser/Parser.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index a716ccc4578..09689b32aeb 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -33,7 +33,6 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.hpack.HpackDecoder; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -76,12 +75,6 @@ public class Parser { try { - if (LOG.isDebugEnabled()) - { - int l=Math.min(buffer.remaining(),16); - LOG.debug("Parsing "+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l)+(l<buffer.remaining()?"...":"")); - } - while (true) { switch (state) @@ -255,7 +248,7 @@ public class Parser @Override public void onConnectionFailure(int error, String reason) { - LOG.warn("onConnectionFailure {},{}",error,reason); + LOG.warn("Connection failure: {}/{}", error, reason); } } } From 75c1322adc7255cf7916a3e928f19875401db157 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 20 Aug 2014 19:19:44 +0200 Subject: [PATCH 254/269] Rewritten close workflow to make sure that connections are correctly closed. --- .../jetty/http2/client/IdleTimeoutTest.java | 29 +- .../{ResetException.java => CloseState.java} | 26 +- .../eclipse/jetty/http2/HTTP2Connection.java | 19 +- .../org/eclipse/jetty/http2/HTTP2Flusher.java | 5 +- .../org/eclipse/jetty/http2/HTTP2Session.java | 302 +++++++++++++++--- .../org/eclipse/jetty/http2/HTTP2Stream.java | 19 +- .../org/eclipse/jetty/http2/ISession.java | 16 +- .../org/eclipse/jetty/http2/api/Session.java | 2 + .../jetty/http2/frames/DisconnectFrame.java | 27 ++ .../eclipse/jetty/http2/frames/FrameType.java | 3 +- .../http2/generator/DisconnectGenerator.java | 35 ++ .../jetty/http2/generator/Generator.java | 1 + .../server/HTTP2ServerConnectionFactory.java | 10 +- .../http2/server/HTTP2ServerSession.java | 2 +- .../http2/server/HttpTransportOverHTTP2.java | 9 +- .../http2/server/AbstractServerTest.java | 117 +++++++ .../eclipse/jetty/http2/server/CloseTest.java | 252 +++++++++++++++ .../jetty/http2/server/HTTP2ServerTest.java | 127 ++------ 18 files changed, 767 insertions(+), 234 deletions(-) rename jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/{ResetException.java => CloseState.java} (60%) create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java create mode 100644 jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java create mode 100644 jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java create mode 100644 jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java index b05b6dd32bb..4e3cf296309 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java @@ -24,7 +24,6 @@ import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -33,6 +32,7 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; @@ -75,7 +75,8 @@ public class IdleTimeoutTest extends AbstractTest @Override public void onClose(Session session, GoAwayFrame frame) { - latch.countDown(); + if (session.isClosed() && ((HTTP2Session)session).isDisconnected()) + latch.countDown(); } }); @@ -91,6 +92,8 @@ public class IdleTimeoutTest extends AbstractTest }, new Stream.Listener.Adapter()); Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + + Thread.sleep(1000); } @Test @@ -113,7 +116,8 @@ public class IdleTimeoutTest extends AbstractTest @Override public void onClose(Session session, GoAwayFrame frame) { - latch.countDown(); + if (session.isClosed() && ((HTTP2Session)session).isDisconnected()) + latch.countDown(); } }); @@ -133,7 +137,7 @@ public class IdleTimeoutTest extends AbstractTest } @Test - public void testServerNotEnforcingIdleTimeoutWithPendingStream() throws Exception + public void testServerNotEnforcingIdleTimeoutWithinCallback() throws Exception { startServer(new ServerSessionListener.Adapter() { @@ -143,6 +147,7 @@ public class IdleTimeoutTest extends AbstractTest try { stream.setIdleTimeout(10 * idleTimeout); + // Stay in the callback for more than the idleTimeout. Thread.sleep(2 * idleTimeout); MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true); @@ -212,7 +217,8 @@ public class IdleTimeoutTest extends AbstractTest @Override public void onClose(Session session, GoAwayFrame frame) { - closeLatch.countDown(); + if (session.isClosed() && ((HTTP2Session)session).isDisconnected()) + closeLatch.countDown(); } }); client.setIdleTimeout(idleTimeout); @@ -230,6 +236,7 @@ public class IdleTimeoutTest extends AbstractTest }, new Stream.Listener.Adapter()); Assert.assertTrue(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + Assert.assertTrue(session.isClosed()); } @Test @@ -248,7 +255,8 @@ public class IdleTimeoutTest extends AbstractTest @Override public void onClose(Session session, GoAwayFrame frame) { - closeLatch.countDown(); + if (session.isClosed() && ((HTTP2Session)session).isDisconnected()) + closeLatch.countDown(); } }); client.setIdleTimeout(idleTimeout); @@ -269,7 +277,7 @@ public class IdleTimeoutTest extends AbstractTest } @Test - public void testClientNotEnforcingIdleTimeoutWithPendingStream() throws Exception + public void testClientNotEnforcingIdleTimeoutWithinCallback() throws Exception { final CountDownLatch closeLatch = new CountDownLatch(1); startServer(new ServerSessionListener.Adapter() @@ -311,6 +319,7 @@ public class IdleTimeoutTest extends AbstractTest { try { + // Stay in the callback for more than idleTimeout. Thread.sleep(2 * idleTimeout); replyLatch.countDown(); } @@ -379,6 +388,9 @@ public class IdleTimeoutTest extends AbstractTest Assert.assertFalse(dataLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); // Stream must be gone. Assert.assertTrue(session.getStreams().isEmpty()); + // Session must not be closed, nor disconnected. + Assert.assertFalse(session.isClosed()); + Assert.assertFalse(((HTTP2Session)session).isDisconnected()); } @Test @@ -420,6 +432,9 @@ public class IdleTimeoutTest extends AbstractTest Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); // Stream must be gone. Assert.assertTrue(session.getStreams().isEmpty()); + // Session must not be closed, nor disconnected. + Assert.assertFalse(session.isClosed()); + Assert.assertFalse(((HTTP2Session)session).isDisconnected()); } @Test diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ResetException.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java similarity index 60% rename from jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ResetException.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java index 8bdf23a19d8..5234a2069df 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ResetException.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java @@ -18,29 +18,7 @@ package org.eclipse.jetty.http2; -public class ResetException extends RuntimeException +public enum CloseState { - public ResetException() - { - } - - public ResetException(String message) - { - super(message); - } - - public ResetException(String message, Throwable cause) - { - super(message, cause); - } - - public ResetException(Throwable cause) - { - super(cause); - } - - public ResetException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) - { - super(message, cause, enableSuppression, writableStackTrace); - } + NOT_CLOSED, LOCALLY_CLOSED, REMOTELY_CLOSED, CLOSED } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index 4115c760018..f6ec101683b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -26,7 +26,6 @@ import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -34,14 +33,6 @@ public class HTTP2Connection extends AbstractConnection { protected static final Logger LOG = Log.getLogger(HTTP2Connection.class); - protected final Callback closeCallback = new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - close(); - } - }; private final ByteBufferPool byteBufferPool; private final Parser parser; private final ISession session; @@ -92,7 +83,7 @@ public class HTTP2Connection extends AbstractConnection } else if (filled < 0) { - shutdown(endPoint, session); + session.onShutdown(); return -1; } else @@ -117,18 +108,12 @@ public class HTTP2Connection extends AbstractConnection } } - private void shutdown(EndPoint endPoint, ISession session) - { - if (!endPoint.isOutputShutdown()) - session.shutdown(); - } - @Override protected boolean onReadTimeout() { if (LOG.isDebugEnabled()) LOG.debug("Idle timeout {}ms expired on {}", getEndPoint().getIdleTimeout(), this); - getSession().close(ErrorCodes.NO_ERROR, "idle_timeout", closeCallback); + session.onIdleTimeout(); return false; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java index 22979de5295..4051cf9c11c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.http2; +import java.io.EOFException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.ArrayDeque; @@ -313,8 +314,6 @@ public class HTTP2Flusher extends IteratingCallback for (Entry entry : queued) closed(entry, x); - - session.disconnect(); } private void closed(Entry entry, Throwable failure) @@ -347,7 +346,7 @@ public class HTTP2Flusher extends IteratingCallback public void reset() { - failed(new ResetException()); + failed(new EOFException("reset")); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 81a7bb00886..6585d071e08 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -26,12 +26,13 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.DisconnectFrame; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.FrameType; import org.eclipse.jetty.http2.frames.GoAwayFrame; @@ -57,14 +58,6 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { private static final Logger LOG = Log.getLogger(HTTP2Session.class); - private final Callback disconnectOnFailure = new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - disconnect(); - } - }; private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>(); private final AtomicInteger streamIds = new AtomicInteger(); private final AtomicInteger lastStreamId = new AtomicInteger(); @@ -72,7 +65,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final AtomicInteger remoteStreamCount = new AtomicInteger(); private final AtomicInteger sendWindow = new AtomicInteger(); private final AtomicInteger recvWindow = new AtomicInteger(); - private final AtomicBoolean closed = new AtomicBoolean(); + private final AtomicReference<CloseState> closed = new AtomicReference<>(CloseState.NOT_CLOSED); private final Scheduler scheduler; private final EndPoint endPoint; private final Generator generator; @@ -144,7 +137,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (getRecvWindow() < 0) { - close(ErrorCodes.FLOW_CONTROL_ERROR, "session_window_exceeded", disconnectOnFailure); + close(ErrorCodes.FLOW_CONTROL_ERROR, "session_window_exceeded", Callback.Adapter.INSTANCE); return false; } @@ -271,7 +264,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener // SPEC: SETTINGS frame MUST be replied. SettingsFrame reply = new SettingsFrame(Collections.<Integer, Integer>emptyMap(), true); - settings(reply, disconnectOnFailure()); + settings(reply, Callback.Adapter.INSTANCE); return false; } @@ -287,26 +280,72 @@ public abstract class HTTP2Session implements ISession, Parser.Listener else { PingFrame reply = new PingFrame(frame.getPayload(), true); - control(null, disconnectOnFailure(), reply); + control(null, Callback.Adapter.INSTANCE, reply); } return false; } + /** + * This method is called when receiving a GO_AWAY from the other peer. + * We check the close state to act appropriately: + * + * * NOT_CLOSED: we move to REMOTELY_CLOSED and queue a disconnect, so + * that the content of the queue is written, and then the connection + * closed. We notify the application after being terminated. + * See {@link HTTP2Session.ControlEntry#succeeded()} + * + * * In all other cases, we do nothing since other methods are already + * performing their actions. + * + * @param frame the GO_AWAY frame that has been received. + * @return whether the parsing will be resumed asynchronously + * @see #close(int, String, Callback) + * @see #onShutdown() + * @see #onIdleTimeout() + */ @Override - public boolean onGoAway(GoAwayFrame frame) + public boolean onGoAway(final GoAwayFrame frame) { if (LOG.isDebugEnabled()) + LOG.debug("Received {}", frame); + + while (true) { - String reason = frame.tryConvertPayload(); - if (LOG.isDebugEnabled()) - LOG.debug("Received {}: {}/'{}'", frame.getType(), frame.getError(), reason); + CloseState current = closed.get(); + switch (current) + { + case NOT_CLOSED: + { + if (closed.compareAndSet(current, CloseState.REMOTELY_CLOSED)) + { + // We received a GO_AWAY, so try to write + // what's in the queue and then disconnect. + control(null, new Callback() + { + @Override + public void succeeded() + { + notifyClose(HTTP2Session.this, frame); + } + + @Override + public void failed(Throwable x) + { + notifyClose(HTTP2Session.this, frame); + } + }, new DisconnectFrame()); + return false; + } + break; + } + default: + { + if (LOG.isDebugEnabled()) + LOG.debug("Ignored {}, already closed", frame); + return false; + } + } } - - flusher.close(); - - notifyClose(this, frame); - - return false; } @Override @@ -331,7 +370,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public void onConnectionFailure(int error, String reason) { - close(error, reason, disconnectOnFailure()); + close(error, reason, Callback.Adapter.INSTANCE); } @Override @@ -401,19 +440,66 @@ public abstract class HTTP2Session implements ISession, Parser.Listener control(getStream(frame.getStreamId()), callback, frame); } + /** + * Invoked internally and by applications to send a GO_AWAY frame to the + * other peer. We check the close state to act appropriately: + * + * * NOT_CLOSED: we move to LOCALLY_CLOSED and queue a GO_AWAY. When the + * GO_AWAY has been written, it will only cause the output to be shut + * down (not the connection closed), so that the application can still + * read frames arriving from the other peer. + * Ideally the other peer will notice the GO_AWAY and close the connection. + * When that happen, we close the connection from {@link #onShutdown()}. + * Otherwise, the idle timeout mechanism will close the connection, see + * {@link #onIdleTimeout()}. + * + * * In all other cases, we do nothing since other methods are already + * performing their actions. + * + * @param error the error code + * @param reason the reason + * @param callback the callback to invoke when the operation is complete + * @see #onGoAway(GoAwayFrame) + * @see #onShutdown() + * @see #onIdleTimeout() + */ @Override public void close(int error, String reason, Callback callback) { - if (closed.compareAndSet(false, true)) + while (true) { - byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); - GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); - if (LOG.isDebugEnabled()) - LOG.debug("Sending {}: {}", frame.getType(), reason); - control(null, callback, frame); + CloseState current = closed.get(); + switch (current) + { + case NOT_CLOSED: + { + if (closed.compareAndSet(current, CloseState.LOCALLY_CLOSED)) + { + byte[] payload = reason == null ? null : reason.getBytes(StandardCharsets.UTF_8); + GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload); + if (LOG.isDebugEnabled()) + LOG.debug("Sending {}", frame); + control(null, callback, frame); + return; + } + break; + } + default: + { + if (LOG.isDebugEnabled()) + LOG.debug("Ignoring close {}/{}, already closed", error, reason); + return; + } + } } } + @Override + public boolean isClosed() + { + return closed.get() != CloseState.NOT_CLOSED; + } + private void control(IStream stream, Callback callback, Frame frame) { control(stream, callback, frame, Frame.EMPTY_ARRAY); @@ -489,7 +575,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener int maxCount = getMaxRemoteStreams(); if (maxCount >= 0 && remoteCount >= maxCount) { - reset(new ResetFrame(streamId, ErrorCodes.REFUSED_STREAM_ERROR), disconnectOnFailure()); + reset(new ResetFrame(streamId, ErrorCodes.REFUSED_STREAM_ERROR), Callback.Adapter.INSTANCE); return null; } if (remoteStreamCount.compareAndSet(remoteCount, remoteCount + 1)) @@ -510,7 +596,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } else { - close(ErrorCodes.PROTOCOL_ERROR, "duplicate_stream", disconnectOnFailure()); + close(ErrorCodes.PROTOCOL_ERROR, "duplicate_stream", Callback.Adapter.INSTANCE); return null; } } @@ -594,32 +680,153 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return pushEnabled; } + /** + * A typical close by a remote peer involves a GO_AWAY frame followed by TCP FIN. + * This method is invoked when the TCP FIN is received, or when an exception is + * thrown while reading, and we check the close state to act appropriately: + * + * * NOT_CLOSED: means that the remote peer did not send a GO_AWAY (abrupt close) + * or there was an exception while reading, and therefore we terminate. + * + * * LOCALLY_CLOSED: we have sent the GO_AWAY to the remote peer, which received + * it and closed the connection; we queue a disconnect to close the connection + * on the local side. + * The GO_AWAY just shutdown the output, so we need this step to make sure the + * connection is closed. See {@link #close(int, String, Callback)}. + * + * * REMOTELY_CLOSED: we received the GO_AWAY, and the TCP FIN afterwards, so we + * do nothing since the handling of the GO_AWAY will take care of closing the + * connection. See {@link #onGoAway(GoAwayFrame)}. + * + * @see #onGoAway(GoAwayFrame) + * @see #close(int, String, Callback) + * @see #onIdleTimeout() + */ @Override - public void shutdown() + public void onShutdown() { if (LOG.isDebugEnabled()) - LOG.debug("Shutting down"); - flusher.close(); + LOG.debug("Shutting down {}", this); + + switch (closed.get()) + { + case NOT_CLOSED: + { + // The other peer did not send a GO_AWAY, no need to be gentle. + if (LOG.isDebugEnabled()) + LOG.debug("Abrupt close for {}", this); + terminate(); + break; + } + case LOCALLY_CLOSED: + { + // We have closed locally, and only shutdown + // the output; now queue a disconnect. + control(null, Callback.Adapter.INSTANCE, new DisconnectFrame()); + break; + } + case REMOTELY_CLOSED: + { + // Nothing to do, the GO_AWAY frame we + // received will close the connection. + break; + } + default: + { + break; + } + } } + /** + * This method is invoked when the idle timeout triggers. We check the close state + * to act appropriately: + * + * * NOT_CLOSED: it's a real idle timeout, we just initiate a close, see + * {@link #close(int, String, Callback)}. + * + * * LOCALLY_CLOSED: we have sent a GO_AWAY and only shutdown the output, but the + * other peer did not close the connection so we never received the TCP FIN, and + * therefore we terminate. + * + * * REMOTELY_CLOSED: the other peer sent us a GO_AWAY, we should have queued a + * disconnect, but for some reason it was not processed (for example, queue was + * stuck because of TCP congestion), therefore we terminate. + * See {@link #onGoAway(GoAwayFrame)}. + * + * @see #onGoAway(GoAwayFrame) + * @see #close(int, String, Callback) + * @see #onShutdown() + */ @Override + public void onIdleTimeout() + { + switch (closed.get()) + { + case NOT_CLOSED: + { + // Real idle timeout, just close. + close(ErrorCodes.NO_ERROR, "idle_timeout", Callback.Adapter.INSTANCE); + break; + } + case LOCALLY_CLOSED: + case REMOTELY_CLOSED: + { + terminate(); + break; + } + default: + { + break; + } + } + } + public void disconnect() { if (LOG.isDebugEnabled()) - LOG.debug("Disconnecting"); + LOG.debug("Disconnecting {}", this); endPoint.close(); } + private void terminate() + { + while (true) + { + CloseState current = closed.get(); + switch (current) + { + case NOT_CLOSED: + case LOCALLY_CLOSED: + case REMOTELY_CLOSED: + { + if (closed.compareAndSet(current, CloseState.CLOSED)) + { + // Close the flusher and disconnect. + flusher.close(); + disconnect(); + return; + } + break; + } + default: + { + return; + } + } + } + } + + public boolean isDisconnected() + { + return !endPoint.isOpen(); + } + private void updateLastStreamId(int streamId) { Atomics.updateMax(lastStreamId, streamId); } - protected Callback disconnectOnFailure() - { - return disconnectOnFailure; - } - protected Stream.Listener notifyNewStream(Stream stream, HeadersFrame frame) { try @@ -684,8 +891,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener @Override public String toString() { - return String.format("%s@%x{queueSize=%d,sendWindow=%s,recvWindow=%s,streams=%d}", getClass().getSimpleName(), - hashCode(), flusher.getQueueSize(), sendWindow, recvWindow, streams.size()); + return String.format("%s@%x{queueSize=%d,sendWindow=%s,recvWindow=%s,streams=%d,%s}", getClass().getSimpleName(), + hashCode(), flusher.getQueueSize(), sendWindow, recvWindow, streams.size(), closed); } private class ControlEntry extends HTTP2Flusher.Entry @@ -725,7 +932,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener } case GO_AWAY: { - flusher.close(); + // We just sent a GO_AWAY, only shutdown the + // output without closing yet, to allow reads. + getEndPoint().shutdownOutput(); + break; + } + case DISCONNECT: + { + terminate(); break; } default: diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index dc19e878072..20b8f36f0fe 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -41,14 +41,6 @@ public class HTTP2Stream extends IdleTimeout implements IStream { private static final Logger LOG = Log.getLogger(HTTP2Stream.class); - private final Callback disconnectOnFailure = new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - session.disconnect(); - } - }; private final AtomicReference<ConcurrentMap<String, Object>> attributes = new AtomicReference<>(); private final AtomicReference<CloseState> closeState = new AtomicReference<>(CloseState.NOT_CLOSED); private final AtomicInteger sendWindow = new AtomicInteger(); @@ -147,8 +139,10 @@ public class HTTP2Stream extends IdleTimeout implements IStream // avoid that its idle timeout is rescheduled. close(); - reset(new ResetFrame(getId(), ErrorCodes.CANCEL_STREAM_ERROR), disconnectOnFailure); + // Tell the other peer that we timed out. + reset(new ResetFrame(getId(), ErrorCodes.CANCEL_STREAM_ERROR), Callback.Adapter.INSTANCE); + // Notify the application. notifyFailure(this, timeout); } @@ -195,7 +189,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream { // It's a bad client, it does not deserve to be // treated gently by just resetting the stream. - session.close(ErrorCodes.FLOW_CONTROL_ERROR, "stream_window_exceeded", disconnectOnFailure); + session.close(ErrorCodes.FLOW_CONTROL_ERROR, "stream_window_exceeded", callback); return false; } @@ -330,9 +324,4 @@ public class HTTP2Stream extends IdleTimeout implements IStream return String.format("%s@%x{id=%d,sendWindow=%s,recvWindow=%s,reset=%b,%s}", getClass().getSimpleName(), hashCode(), getId(), sendWindow, recvWindow, reset, closeState); } - - private enum CloseState - { - NOT_CLOSED, LOCALLY_CLOSED, REMOTELY_CLOSED, CLOSED - } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index c891abed16b..8f9e5dfc06a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -46,7 +46,19 @@ public interface ISession extends Session public boolean isPushEnabled(); - public void shutdown(); + /** + * Callback invoked when the connection reads -1. + * + * @see #onIdleTimeout() + * @see #close(int, String, Callback) + */ + public void onShutdown(); - public void disconnect(); + /** + * Callback invoked when the idle timeout expires. + * + * @see #onShutdown() + * @see #close(int, String, Callback) + */ + public void onIdleTimeout(); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java index e9df4786657..b09c417ceac 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java @@ -39,6 +39,8 @@ public interface Session public void close(int error, String payload, Callback callback); + public boolean isClosed(); + public Collection<Stream> getStreams(); public Stream getStream(int streamId); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java new file mode 100644 index 00000000000..4440c245777 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java @@ -0,0 +1,27 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class DisconnectFrame extends Frame +{ + public DisconnectFrame() + { + super(FrameType.DISCONNECT); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java index 9d61ac4f900..0414dc67375 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java @@ -34,7 +34,8 @@ public enum FrameType WINDOW_UPDATE(8), CONTINUATION(9), // Synthetic frames only needed by the implementation. - PREFACE(10); + PREFACE(10), + DISCONNECT(11); public static FrameType from(int type) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java new file mode 100644 index 00000000000..bdece50e6ad --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java @@ -0,0 +1,35 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.generator; + +import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.io.ByteBufferPool; + +public class DisconnectGenerator extends FrameGenerator +{ + public DisconnectGenerator() + { + super(null); + } + + @Override + public void generate(ByteBufferPool.Lease lease, Frame frame) + { + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index bed1558477c..0b5f8ff16f6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -55,6 +55,7 @@ public class Generator this.generators[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateGenerator(headerGenerator); this.generators[FrameType.CONTINUATION.getType()] = null; // TODO this.generators[FrameType.PREFACE.getType()] = new PrefaceGenerator(); + this.generators[FrameType.DISCONNECT.getType()] = new DisconnectGenerator(); this.dataGenerator = new DataGenerator(headerGenerator); } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 5c39454ff18..f6c9a927265 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -23,7 +23,6 @@ import java.util.Map; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCodes; -import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; @@ -142,14 +141,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF private void close(Stream stream, String reason) { final Session session = stream.getSession(); - session.close(ErrorCodes.PROTOCOL_ERROR, reason, new Callback.Adapter() - { - @Override - public void failed(Throwable x) - { - ((ISession)session).disconnect(); - } - }); + session.close(ErrorCodes.PROTOCOL_ERROR, reason, Callback.Adapter.INSTANCE); } } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index fced76c03a9..2d74f18602d 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -62,7 +62,7 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis settings = Collections.emptyMap(); SettingsFrame frame = new SettingsFrame(settings, false); // TODO: consider sending a WINDOW_UPDATE to enlarge the session send window of the client. - control(null, disconnectOnFailure(), frame, Frame.EMPTY_ARRAY); + control(null, Callback.Adapter.INSTANCE, frame, Frame.EMPTY_ARRAY); return false; } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 05c66b0ac10..791aeb18468 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -25,12 +25,13 @@ import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.IStream; -import org.eclipse.jetty.http2.ResetException; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; @@ -126,7 +127,6 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (LOG.isDebugEnabled()) LOG.debug("Could not push " + request, x); - stream.getSession().disconnect(); } }); } @@ -167,8 +167,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (LOG.isDebugEnabled()) LOG.debug("HTTP2 Response #{} aborted", stream.getId()); - if (!(failure instanceof ResetException)) - stream.getSession().disconnect(); + if (!stream.isReset()) + stream.reset(new ResetFrame(stream.getId(), ErrorCodes.INTERNAL_ERROR), Callback.Adapter.INSTANCE); } private class CommitCallback implements Callback @@ -185,7 +185,6 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (LOG.isDebugEnabled()) LOG.debug("HTTP2 Response #" + stream.getId() + " failed to commit", x); - stream.getSession().disconnect(); } } } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java new file mode 100644 index 00000000000..ef39b6c182c --- /dev/null +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java @@ -0,0 +1,117 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import javax.servlet.http.HttpServlet; + +import org.eclipse.jetty.http.HostPortHttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.After; + +public class AbstractServerTest +{ + protected ServerConnector connector; + protected ByteBufferPool byteBufferPool; + protected Generator generator; + protected Server server; + protected String path; + + protected void startServer(HttpServlet servlet) throws Exception + { + prepareServer(new HTTP2ServerConnectionFactory(new HttpConfiguration())); + ServletContextHandler context = new ServletContextHandler(server, "/"); + context.addServlet(new ServletHolder(servlet), path); + server.start(); + } + + protected void startServer(ServerSessionListener listener) throws Exception + { + prepareServer(new RawHTTP2ServerConnectionFactory(listener)); + server.start(); + } + + private void prepareServer(ConnectionFactory connectionFactory) + { + QueuedThreadPool serverExecutor = new QueuedThreadPool(); + serverExecutor.setName("server"); + server = new Server(serverExecutor); + connector = new ServerConnector(server, connectionFactory); + server.addConnector(connector); + path = "/test"; + byteBufferPool = new MappedByteBufferPool(); + generator = new Generator(byteBufferPool); + } + + protected MetaData.Request newRequest(String method, HttpFields fields) + { + String host = "localhost"; + int port = connector.getLocalPort(); + String authority = host + ":" + port; + return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields); + } + + @After + public void dispose() throws Exception + { + server.stop(); + } + + protected boolean parseResponse(Socket client, Parser parser) throws IOException + { + byte[] buffer = new byte[2048]; + InputStream input = client.getInputStream(); + client.setSoTimeout(1000); + while (true) + { + try + { + int read = input.read(buffer); + if (read < 0) + return true; + parser.parse(ByteBuffer.wrap(buffer, 0, read)); + if (client.isClosed()) + return true; + } + catch (SocketTimeoutException x) + { + return false; + } + } + } +} diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java new file mode 100644 index 00000000000..f67a285b57e --- /dev/null +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java @@ -0,0 +1,252 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.server; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.ErrorCodes; +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.GoAwayFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PrefaceFrame; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; +import org.junit.Assert; +import org.junit.Test; + +public class CloseTest extends AbstractServerTest +{ + @Test + public void testClientAbruptlyClosesConnection() throws Exception + { + final CountDownLatch closeLatch = new CountDownLatch(1); + final AtomicReference<Session> sessionRef = new AtomicReference<>(); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + try + { + sessionRef.set(stream.getSession()); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + // Reply with HEADERS. + stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.Adapter.INSTANCE); + closeLatch.await(5, TimeUnit.SECONDS); + return null; + } + catch (InterruptedException x) + { + return null; + } + } + }); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.control(lease, new PrefaceFrame()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + generator.control(lease, new HeadersFrame(1, metaData, null, true)); + + try (Socket client = new Socket("localhost", connector.getLocalPort())) + { + OutputStream output = client.getOutputStream(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + output.write(BufferUtil.toArray(buffer)); + } + + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onHeaders(HeadersFrame frame) + { + try + { + // Close the connection just after + // receiving the response headers. + client.close(); + closeLatch.countDown(); + return false; + } + catch (IOException x) + { + return false; + } + } + }, 4096, 8192); + + parseResponse(client, parser); + + // We need to give some time to the server to receive and process the TCP FIN. + Thread.sleep(1000); + + Session session = sessionRef.get(); + Assert.assertTrue(session.isClosed()); + Assert.assertTrue(((HTTP2Session)session).isDisconnected()); + } + } + + @Test + public void testClientSendsGoAwayButDoesNotCloseConnectionServerCloses() throws Exception + { + final AtomicReference<Session> sessionRef = new AtomicReference<>(); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + sessionRef.set(stream.getSession()); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.Adapter.INSTANCE); + return null; + } + }); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.control(lease, new PrefaceFrame()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + generator.control(lease, new HeadersFrame(1, metaData, null, true)); + generator.control(lease, new GoAwayFrame(1, ErrorCodes.NO_ERROR, "OK".getBytes("UTF-8"))); + + try (Socket client = new Socket("localhost", connector.getLocalPort())) + { + OutputStream output = client.getOutputStream(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + output.write(BufferUtil.toArray(buffer)); + } + + // Don't close the connection; the server should close. + + final CountDownLatch responseLatch = new CountDownLatch(1); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onHeaders(HeadersFrame frame) + { + // Even if we sent the GO_AWAY immediately after the + // HEADERS, the server is able to send us the response. + responseLatch.countDown(); + return false; + } + }, 4096, 8192); + + parseResponse(client, parser); + + Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); + + // Wait for the server to close. + Thread.sleep(1000); + + // Client received the TCP FIN from server. + Assert.assertEquals(-1, client.getInputStream().read()); + + // Server is closed. + Session session = sessionRef.get(); + Assert.assertTrue(session.isClosed()); + Assert.assertTrue(((HTTP2Session)session).isDisconnected()); + } + } + + @Test + public void testServerSendsGoAwayClientDoesNotCloseServerIdleTimeout() throws Exception + { + final long idleTimeout = 1000; + final AtomicReference<Session> sessionRef = new AtomicReference<>(); + startServer(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + stream.setIdleTimeout(10 * idleTimeout); + sessionRef.set(stream.getSession()); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()); + stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.Adapter.INSTANCE); + stream.getSession().close(ErrorCodes.NO_ERROR, "OK", Callback.Adapter.INSTANCE); + return null; + } + }); + connector.setIdleTimeout(idleTimeout); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.control(lease, new PrefaceFrame()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + generator.control(lease, new HeadersFrame(1, metaData, null, true)); + + try (Socket client = new Socket("localhost", connector.getLocalPort())) + { + OutputStream output = client.getOutputStream(); + for (ByteBuffer buffer : lease.getByteBuffers()) + { + output.write(BufferUtil.toArray(buffer)); + } + + final CountDownLatch responseLatch = new CountDownLatch(1); + final CountDownLatch closeLatch = new CountDownLatch(1); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public boolean onHeaders(HeadersFrame frame) + { + responseLatch.countDown(); + return false; + } + + @Override + public boolean onGoAway(GoAwayFrame frame) + { + closeLatch.countDown(); + return false; + } + }, 4096, 8192); + + parseResponse(client, parser); + + Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS)); + + // Don't close the connection. + + // Wait for the server to idle timeout. + Thread.sleep(2 * idleTimeout); + + // Client received the TCP FIN from server. + Assert.assertEquals(-1, client.getInputStream().read()); + + // Server is closed. + Session session = sessionRef.get(); + Assert.assertTrue(session.isClosed()); + Assert.assertTrue(((HTTP2Session)session).isDisconnected()); + } + } +} diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index 4befeb48029..e5c8b11c532 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -19,10 +19,8 @@ package org.eclipse.jetty.http2.server; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; -import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; @@ -33,11 +31,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpScheme; -import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCodes; import org.eclipse.jetty.http2.frames.DataFrame; @@ -46,67 +40,25 @@ import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.http2.frames.PrefaceFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; -import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.BufferUtil; -import org.junit.After; import org.junit.Assert; import org.junit.Test; -public class HTTP2ServerTest +public class HTTP2ServerTest extends AbstractServerTest { - private Server server; - private ServerConnector connector; - private String path; - private ByteBufferPool byteBufferPool; - private Generator generator; - - private void startServer(HttpServlet servlet) throws Exception - { - server = new Server(); - connector = new ServerConnector(server, new HTTP2ServerConnectionFactory(new HttpConfiguration())); - server.addConnector(connector); - - ServletContextHandler context = new ServletContextHandler(server, "/"); - path = "/test"; - context.addServlet(new ServletHolder(servlet), path); - - byteBufferPool = new MappedByteBufferPool(); - generator = new Generator(byteBufferPool); - - server.start(); - } - - @After - public void dispose() throws Exception - { - server.stop(); - } - @Test public void testNoPrefaceBytes() throws Exception { startServer(new HttpServlet(){}); - String host = "localhost"; - int port = connector.getLocalPort(); - HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP, new HostPortHttpField(host + ":" + port), - path, HttpVersion.HTTP_2, fields); - HeadersFrame request = new HeadersFrame(1, metaData, null, true); + // No preface bytes. + MetaData.Request metaData = newRequest("GET", new HttpFields()); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.control(lease, request); + generator.control(lease, new HeadersFrame(1, metaData, null, true)); - // No preface bytes - - try (Socket client = new Socket(host, port)) + try (Socket client = new Socket("localhost", connector.getLocalPort())) { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -144,17 +96,12 @@ public class HTTP2ServerTest } }); - String host = "localhost"; - int port = connector.getLocalPort(); - HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP, new HostPortHttpField(host + ":" + port), - path, HttpVersion.HTTP_2, fields); - HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.control(lease, request); - lease.prepend(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); + generator.control(lease, new PrefaceFrame()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + generator.control(lease, new HeadersFrame(1, metaData, null, true)); - try (Socket client = new Socket(host, port)) + try (Socket client = new Socket("localhost", connector.getLocalPort())) { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -207,17 +154,12 @@ public class HTTP2ServerTest } }); - String host = "localhost"; - int port = connector.getLocalPort(); - HttpFields fields = new HttpFields(); - MetaData.Request metaData = new MetaData.Request(HttpMethod.GET.asString(),HttpScheme.HTTP, new HostPortHttpField(host + ":" + port), - path, HttpVersion.HTTP_2, fields); - HeadersFrame request = new HeadersFrame(1, metaData, null, true); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.control(lease, request); - lease.prepend(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); + generator.control(lease, new PrefaceFrame()); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + generator.control(lease, new HeadersFrame(1, metaData, null, true)); - try (Socket client = new Socket(host, port)) + try (Socket client = new Socket("localhost", connector.getLocalPort())) { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -273,17 +215,14 @@ public class HTTP2ServerTest { startServer(new HttpServlet(){}); - String host = "localhost"; - int port = connector.getLocalPort(); - PingFrame frame = new PingFrame(new byte[8], false); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.control(lease, frame); + generator.control(lease, new PrefaceFrame()); + generator.control(lease, new PingFrame(new byte[8], false)); // Modify the length of the frame to a wrong one. - lease.getByteBuffers().get(0).putShort(0, (short)7); - lease.prepend(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); + lease.getByteBuffers().get(1).putShort(0, (short)7); final CountDownLatch latch = new CountDownLatch(1); - try (Socket client = new Socket(host, port)) + try (Socket client = new Socket("localhost", connector.getLocalPort())) { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -313,17 +252,14 @@ public class HTTP2ServerTest { startServer(new HttpServlet(){}); - String host = "localhost"; - int port = connector.getLocalPort(); - PingFrame frame = new PingFrame(new byte[8], false); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.control(lease, frame); + generator.control(lease, new PrefaceFrame()); + generator.control(lease, new PingFrame(new byte[8], false)); // Modify the streamId of the frame to non zero. - lease.getByteBuffers().get(0).putInt(4, 1); - lease.prepend(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); + lease.getByteBuffers().get(1).putInt(4, 1); final CountDownLatch latch = new CountDownLatch(1); - try (Socket client = new Socket(host, port)) + try (Socket client = new Socket("localhost", connector.getLocalPort())) { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -347,25 +283,4 @@ public class HTTP2ServerTest Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } } - - private boolean parseResponse(Socket client, Parser parser) throws IOException - { - byte[] buffer = new byte[2048]; - InputStream input = client.getInputStream(); - client.setSoTimeout(1000); - while (true) - { - try - { - int read = input.read(buffer); - if (read < 0) - return true; - parser.parse(ByteBuffer.wrap(buffer, 0, read)); - } - catch (SocketTimeoutException x) - { - return false; - } - } - } } From c07ea68b51d1cda14dac87bd21c9859e2620288b Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 20 Aug 2014 19:35:27 +0200 Subject: [PATCH 255/269] Improved configurability of stream idle timeout. --- .../http2/client/HTTP2ClientSession.java | 2 +- .../org/eclipse/jetty/http2/HTTP2Session.java | 32 ++++++++++++++++--- .../AbstractHTTP2ServerConnectionFactory.java | 8 ++++- .../http2/server/HTTP2ServerSession.java | 4 +-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index 6d547e4bda9..8e5d06162d7 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -37,7 +37,7 @@ public class HTTP2ClientSession extends HTTP2Session public HTTP2ClientSession(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl) { - super(scheduler, endPoint, generator, listener, flowControl, -1, 1); + super(scheduler, endPoint, generator, listener, flowControl, 1); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 6585d071e08..78b6ad833a0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -74,9 +74,10 @@ public abstract class HTTP2Session implements ISession, Parser.Listener private final HTTP2Flusher flusher; private int maxLocalStreams; private int maxRemoteStreams; + private long streamIdleTimeout; private boolean pushEnabled; - public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int maxStreams, int initialStreamId) + public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControl flowControl, int initialStreamId) { this.scheduler = scheduler; this.endPoint = endPoint; @@ -84,9 +85,10 @@ public abstract class HTTP2Session implements ISession, Parser.Listener this.listener = listener; this.flowControl = flowControl; this.flusher = new HTTP2Flusher(this); - this.maxLocalStreams = maxStreams; - this.maxRemoteStreams = maxStreams; + this.maxLocalStreams = -1; + this.maxRemoteStreams = -1; this.streamIds.set(initialStreamId); + this.streamIdleTimeout = endPoint.getIdleTimeout(); this.sendWindow.set(FlowControl.DEFAULT_WINDOW_SIZE); this.recvWindow.set(FlowControl.DEFAULT_WINDOW_SIZE); this.pushEnabled = true; // SPEC: by default, push is enabled. @@ -97,6 +99,16 @@ public abstract class HTTP2Session implements ISession, Parser.Listener return flowControl; } + public int getMaxLocalStreams() + { + return maxLocalStreams; + } + + public void setMaxLocalStreams(int maxLocalStreams) + { + this.maxLocalStreams = maxLocalStreams; + } + public int getMaxRemoteStreams() { return maxRemoteStreams; @@ -107,6 +119,16 @@ public abstract class HTTP2Session implements ISession, Parser.Listener this.maxRemoteStreams = maxRemoteStreams; } + public long getStreamIdleTimeout() + { + return streamIdleTimeout; + } + + public void setStreamIdleTimeout(long streamIdleTimeout) + { + this.streamIdleTimeout = streamIdleTimeout; + } + public EndPoint getEndPoint() { return endPoint; @@ -553,7 +575,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener IStream stream = newStream(streamId); if (streams.putIfAbsent(streamId, stream) == null) { - stream.setIdleTimeout(endPoint.getIdleTimeout()); + stream.setIdleTimeout(getStreamIdleTimeout()); flowControl.onNewStream(stream); if (LOG.isDebugEnabled()) LOG.debug("Created local {}", stream); @@ -588,7 +610,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (streams.putIfAbsent(streamId, stream) == null) { updateLastStreamId(streamId); - stream.setIdleTimeout(endPoint.getIdleTimeout()); + stream.setIdleTimeout(getStreamIdleTimeout()); flowControl.onNewStream(stream); if (LOG.isDebugEnabled()) LOG.debug("Created remote {}", stream); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index cd4c12254d3..289580150f3 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -82,7 +82,13 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne Generator generator = new Generator(connector.getByteBufferPool(), getMaxHeaderTableSize()); HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, generator, listener, - new HTTP2FlowControl(getInitialStreamWindow()), getMaxConcurrentStreams()); + new HTTP2FlowControl(getInitialStreamWindow())); + session.setMaxLocalStreams(getMaxConcurrentStreams()); + session.setMaxRemoteStreams(getMaxConcurrentStreams()); + long idleTimeout = endPoint.getIdleTimeout(); + if (idleTimeout > 0) + idleTimeout /= 2; + session.setStreamIdleTimeout(idleTimeout); Parser parser = newServerParser(connector.getByteBufferPool(), session); HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(), diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index 2d74f18602d..5e49d4cbe16 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -47,9 +47,9 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis private final ServerSessionListener listener; - public HTTP2ServerSession(Scheduler scheduler, EndPoint endPoint, Generator generator, ServerSessionListener listener, FlowControl flowControl, int maxStreams) + public HTTP2ServerSession(Scheduler scheduler, EndPoint endPoint, Generator generator, ServerSessionListener listener, FlowControl flowControl) { - super(scheduler, endPoint, generator, listener, flowControl, maxStreams, 2); + super(scheduler, endPoint, generator, listener, flowControl, 2); this.listener = listener; } From 17c8f71724ff1dadf575a208ed5e0fdc4c1e7143 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Thu, 21 Aug 2014 11:27:51 +0200 Subject: [PATCH 256/269] Renamed onConnect() to onAccept() to reflect its server-side role. --- .../eclipse/jetty/http2/api/server/ServerSessionListener.java | 4 ++-- .../http2/server/AbstractHTTP2ServerConnectionFactory.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java index 3eb90e8867b..54ddacbdfee 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java @@ -22,12 +22,12 @@ import org.eclipse.jetty.http2.api.Session; public interface ServerSessionListener extends Session.Listener { - public void onConnect(Session session); + public void onAccept(Session session); public static class Adapter extends Session.Listener.Adapter implements ServerSessionListener { @Override - public void onConnect(Session session) + public void onAccept(Session session) { } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 289580150f3..6f5b7a58a3c 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -122,7 +122,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne { try { - listener.onConnect(session); + listener.onAccept(session); } catch (Throwable x) { From 790678d4605c59c85a4be6894a937b41208c325a Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Thu, 21 Aug 2014 12:27:58 +0200 Subject: [PATCH 257/269] Moved NPN module files in the right directory after merge. --- .../main/config/modules/protonego-impl/npn-1.7.0_65.mod | 0 .../main/config/modules/protonego-impl/npn-1.7.0_67.mod | 0 .../main/config/modules/protonego-impl/npn-1.7.0_60.mod | 8 -------- 3 files changed, 8 deletions(-) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod (100%) rename {jetty-spdy/spdy-http-server => jetty-npn/jetty-npn-server}/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod (100%) delete mode 100644 jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod b/jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod similarity index 100% rename from jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod rename to jetty-npn/jetty-npn-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod deleted file mode 100644 index 639c70e3ffd..00000000000 --- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar - -[exec] --Xbootclasspath/p:lib/npn/npn-boot-1.1.7.v20140316.jar From 2cdc48e97f21b26dca49be8965cb739806706e7d Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Thu, 21 Aug 2014 15:18:10 +0200 Subject: [PATCH 258/269] Moved NPNModuleTest to module 'jetty-npn-server'. This follows where npn module files have been moved to. --- jetty-npn/jetty-npn-server/pom.xml | 6 ++++++ .../eclipse/jetty/npn}/server/NPNModuleTest.java | 15 +++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) rename {jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy => jetty-npn/jetty-npn-server/src/test/java/org/eclipse/jetty/npn}/server/NPNModuleTest.java (94%) diff --git a/jetty-npn/jetty-npn-server/pom.xml b/jetty-npn/jetty-npn-server/pom.xml index 3c606d34a27..7f0590f14a6 100644 --- a/jetty-npn/jetty-npn-server/pom.xml +++ b/jetty-npn/jetty-npn-server/pom.xml @@ -39,6 +39,12 @@ <version>${npn.api.version}</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-start</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>org.eclipse.jetty.toolchain</groupId> <artifactId>jetty-test-helper</artifactId> diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java b/jetty-npn/jetty-npn-server/src/test/java/org/eclipse/jetty/npn/server/NPNModuleTest.java similarity index 94% rename from jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java rename to jetty-npn/jetty-npn-server/src/test/java/org/eclipse/jetty/npn/server/NPNModuleTest.java index b9c74a63ce5..f1c8b1a2a56 100644 --- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java +++ b/jetty-npn/jetty-npn-server/src/test/java/org/eclipse/jetty/npn/server/NPNModuleTest.java @@ -16,10 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.spdy.server; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +package org.eclipse.jetty.npn.server; import java.io.File; import java.io.FileOutputStream; @@ -47,6 +44,12 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + @RunWith(Parameterized.class) public class NPNModuleTest { @@ -69,7 +72,7 @@ public class NPNModuleTest @Parameters(name = "{index}: mod:{0}") public static List<Object[]> data() { - File npnBootModDir = MavenTestingUtils.getProjectDir("../spdy-http-server/src/main/config/modules/protonego-impl"); + File npnBootModDir = MavenTestingUtils.getProjectDir("src/main/config/modules/protonego-impl"); List<Object[]> data = new ArrayList<>(); for (File file : npnBootModDir.listFiles()) { @@ -89,7 +92,7 @@ public class NPNModuleTest @BeforeClass public static void initBaseHome() throws IOException { - File homeDir = MavenTestingUtils.getProjectDir("../spdy-http-server/src/main/config"); + File homeDir = MavenTestingUtils.getProjectDir("src/main/config"); File baseDir = MavenTestingUtils.getTargetTestingDir(NPNModuleTest.class.getName()); FS.ensureEmpty(baseDir); From e5c1d66916549c0b796d1ae17c6b8609d5338b8d Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 22 Aug 2014 16:25:20 +1000 Subject: [PATCH 259/269] avoid default port in http2 push --- .../java/org/eclipse/jetty/http/HttpScheme.java | 2 +- .../main/java/org/eclipse/jetty/http/HttpURI.java | 14 ++++++++++++++ .../java/org/eclipse/jetty/server/Dispatcher.java | 8 +------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java index 13f2a8d3fa5..07fb7f905f4 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java @@ -61,7 +61,7 @@ public enum HttpScheme /* ------------------------------------------------------------ */ public boolean is(String s) { - return _string.equalsIgnoreCase(s); + return s!=null && _string.equalsIgnoreCase(s); } public String asString() diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index 26ad8e7b592..d476c5f0931 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -75,6 +75,20 @@ public class HttpURI String _uri; String _decodedPath; + /* ------------------------------------------------------------ */ + /** + * Construct a normalized URI. + * Port is not set if it is the default port. + */ + public static HttpURI createHttpURI(String scheme, String host, int port, String path, String param, String query, String fragment) + { + if (port==80 && HttpScheme.HTTP.is(scheme)) + port=0; + if (port==443 && HttpScheme.HTTPS.is(scheme)) + port=0; + return new HttpURI(scheme,host,port,path,param,query,fragment); + } + /* ------------------------------------------------------------ */ public HttpURI() { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java index 4a50fa09cef..64d5bdb9155 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java @@ -231,13 +231,7 @@ public class Dispatcher implements RequestDispatcher query=query+"&"+_uri.getQuery(); // TODO is this correct semantic? } - int port=request.getServerPort(); - if (port==80 && HttpScheme.HTTP.is(request.getScheme())) - port=0; - if (port==443 && HttpScheme.HTTPS.is(request.getScheme())) - port=0; - - HttpURI uri = new HttpURI(request.getScheme(),request.getServerName(),request.getServerPort(),_uri.getPath(),baseRequest.getHttpURI().getParam(),query,null); + HttpURI uri = HttpURI.createHttpURI(request.getScheme(),request.getServerName(),request.getServerPort(),_uri.getPath(),baseRequest.getHttpURI().getParam(),query,null); MetaData.Request push = new MetaData.Request(HttpMethod.GET.asString(),uri,baseRequest.getHttpVersion(),fields); From d8e6331434fbb6025301f06f03230c6f6cad7676 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Wed, 27 Aug 2014 17:33:27 +1000 Subject: [PATCH 260/269] 442477 Allow Symlink aliases by default --- .../jetty/server/handler/ContextHandler.java | 71 +++++-------------- .../ContextHandlerGetResourceTest.java | 2 + .../jetty/servlet/DefaultServletTest.java | 5 +- 3 files changed, 23 insertions(+), 55 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 9dc9794fa40..ccb2fce0467 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -99,7 +99,9 @@ import org.eclipse.jetty.util.resource.Resource; * and org.eclipse.jetty.server.Request.maxFormContentSize. These can also be configured with {@link #setMaxFormContentSize(int)} and {@link #setMaxFormKeys(int)} * <p> * This servers executore is made available via a context attributed "org.eclipse.jetty.server.Executor". - * + * <p> + * By default, the context is created with alias checkers for {@link AllowSymLinkAliasChecker} (unix only) and {@link ApproveNonExistentDirectoryAliases}. + * If these alias checkers are not required, then {@link #clearAliasChecks()} or {@link #setAliasChecks(List)} should be called. * @org.apache.xbean.XBean description="Creates a basic HTTP context" */ @ManagedObject("URI Context") @@ -193,11 +195,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu */ public ContextHandler() { - super(); - _scontext = new Context(); - _attributes = new AttributesMap(); - _initParams = new HashMap<String, String>(); - addAliasCheck(new ApproveNonExistentDirectoryAliases()); + this((Context)null); } /* ------------------------------------------------------------ */ @@ -207,10 +205,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu protected ContextHandler(Context context) { super(); - _scontext = context; + _scontext = context==null?new Context():context; _attributes = new AttributesMap(); _initParams = new HashMap<String, String>(); addAliasCheck(new ApproveNonExistentDirectoryAliases()); + if (File.separatorChar=='/') + addAliasCheck(new AllowSymLinkAliasChecker()); } /* ------------------------------------------------------------ */ @@ -1794,6 +1794,16 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu _aliasChecks.clear(); _aliasChecks.addAll(checks); } + + /* ------------------------------------------------------------ */ + /** + * clear the list of AliasChecks + */ + public void clearAliasChecks() + { + _aliasChecks.clear(); + } + /* ------------------------------------------------------------ */ /** @@ -2746,53 +2756,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu return true; } } - - /* ------------------------------------------------------------ */ - /** Approve Aliases with same suffix. - * Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would be - * approved because both the resource and alias end with ".html". - */ - @Deprecated - public static class ApproveSameSuffixAliases implements AliasCheck - { - { - LOG.warn("ApproveSameSuffixAlias is not safe for production"); - } - - @Override - public boolean check(String path, Resource resource) - { - int dot = path.lastIndexOf('.'); - if (dot<0) - return false; - String suffix=path.substring(dot); - return resource.toString().endsWith(suffix); - } - } - - - /* ------------------------------------------------------------ */ - /** Approve Aliases with a path prefix. - * Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html would be - * approved because both the resource and alias end with "/foobar.html". - */ - @Deprecated - public static class ApprovePathPrefixAliases implements AliasCheck - { - { - LOG.warn("ApprovePathPrefixAliases is not safe for production"); - } - - @Override - public boolean check(String path, Resource resource) - { - int slash = path.lastIndexOf('/'); - if (slash<0 || slash==path.length()-1) - return false; - String suffix=path.substring(slash); - return resource.toString().endsWith(suffix); - } - } /* ------------------------------------------------------------ */ /** Approve Aliases of a non existent directory. diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java index aace3e77797..9bd1db2dc9f 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java @@ -86,6 +86,8 @@ public class ContextHandlerGetResourceTest server = new Server(); context =new ContextHandler("/"); + context.clearAliasChecks(); + context.addAliasCheck(new ContextHandler.ApproveNonExistentDirectoryAliases()); context.setBaseResource(Resource.newResource(docroot)); context.addAliasCheck(new ContextHandler.AliasCheck() { diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java index 8cc231a3913..9f6eb9745dc 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java @@ -41,6 +41,7 @@ import org.eclipse.jetty.http.DateGenerator; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; @@ -431,11 +432,13 @@ public class DefaultServletTest if (!OS.IS_WINDOWS) { + context.clearAliasChecks(); + Files.createSymbolicLink(link.toPath(),foobar.toPath()); response = connector.getResponses("GET /context/link.txt HTTP/1.0\r\n\r\n"); assertResponseContains("404", response); - context.addAliasCheck(new ContextHandler.ApproveAliases()); + context.addAliasCheck(new AllowSymLinkAliasChecker()); response = connector.getResponses("GET /context/link.txt HTTP/1.0\r\n\r\n"); assertResponseContains("Foo Bar", response); From a4debf68c436efa98d7498e4e004aef48defd2f0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 29 Aug 2014 16:03:32 +1000 Subject: [PATCH 261/269] fixed merge --- .../org/eclipse/jetty/server/handler/IdleTimeoutHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java index e0b0276e46d..ccce50d8800 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java @@ -80,7 +80,7 @@ public class IdleTimeoutHandler extends HandlerWrapper @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - final HttpChannel<?> channel = baseRequest.getHttpChannel(); + final HttpChannel channel = baseRequest.getHttpChannel(); final long idle_timeout=baseRequest.getHttpChannel().getIdleTimeout(); channel.setIdleTimeout(_idleTimeoutMs); From 277ca5c06585dae9157953d72bc0b040d36262c0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Fri, 29 Aug 2014 17:54:28 +1000 Subject: [PATCH 262/269] fixed merge --- .../server/handler/IdleTimeoutHandler.java | 54 +++++++++---------- tests/test-quickstart/pom.xml | 2 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java index ccce50d8800..17d960e80c7 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java @@ -90,35 +90,35 @@ public class IdleTimeoutHandler extends HandlerWrapper } finally { - if (_applyToAsync && request.isAsyncStarted()) + if (_applyToAsync && request.isAsyncStarted()) + { + request.getAsyncContext().addListener(new AsyncListener() { - request.getAsyncContext().addListener(new AsyncListener() + @Override + public void onTimeout(AsyncEvent event) throws IOException + { + } + + @Override + public void onStartAsync(AsyncEvent event) throws IOException { - @Override - public void onTimeout(AsyncEvent event) throws IOException - { - } - - @Override - public void onStartAsync(AsyncEvent event) throws IOException - { - } - - @Override - public void onError(AsyncEvent event) throws IOException - { - channel.setIdleTimeout(idle_timeout); - } - - @Override - public void onComplete(AsyncEvent event) throws IOException - { - channel.setIdleTimeout(idle_timeout); - } - }); - } - else - channel.setIdleTimeout(idle_timeout); + } + + @Override + public void onError(AsyncEvent event) throws IOException + { + channel.setIdleTimeout(idle_timeout); + } + + @Override + public void onComplete(AsyncEvent event) throws IOException + { + channel.setIdleTimeout(idle_timeout); + } + }); + } + else + channel.setIdleTimeout(idle_timeout); } } } diff --git a/tests/test-quickstart/pom.xml b/tests/test-quickstart/pom.xml index cba967c175f..7848e2deedf 100644 --- a/tests/test-quickstart/pom.xml +++ b/tests/test-quickstart/pom.xml @@ -12,7 +12,7 @@ <description>Jetty Quick Start Test</description> <url>http://www.eclipse.org/jetty</url> <properties> - <bundle-symbolic-name>${project.groupId}.examples.quickstart</bundle-symbolic-name> + <bundle-symbolic-name>${project.groupId}.tests.quickstart</bundle-symbolic-name> </properties> <dependencies> <dependency> From 5370f3c8cb0127bfb053be07da93177c0a62f382 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Mon, 1 Sep 2014 12:06:18 +0200 Subject: [PATCH 263/269] 442950 - Embedded Jetty client requests to localhost hangs with high cpu usage (NIO OP_CONNECT Solaris/Sparc). --- .../java/org/eclipse/jetty/http2/client/HTTP2Client.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index b45a06ad573..6ab8d2799f7 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -90,7 +90,6 @@ public class HTTP2Client extends ContainerLifeCycle SocketChannel channel = SocketChannel.open(); channel.socket().setTcpNoDelay(true); channel.configureBlocking(false); - channel.connect(address); Map<String, Object> context = new HashMap<>(); context.put(HTTP2ClientConnectionFactory.CLIENT_CONTEXT_KEY, this); @@ -101,7 +100,10 @@ public class HTTP2Client extends ContainerLifeCycle context.put(SslClientConnectionFactory.SSL_PEER_HOST_CONTEXT_KEY, address.getHostString()); context.put(SslClientConnectionFactory.SSL_PEER_PORT_CONTEXT_KEY, address.getPort()); - selector.connect(channel, context); + if (channel.connect(address)) + selector.accept(channel, context); + else + selector.connect(channel, context); } catch (Throwable x) { From 07ec47adfac619308f71047808380322c8b46352 Mon Sep 17 00:00:00 2001 From: Greg Wilkins <gregw@intalio.com> Date: Thu, 4 Sep 2014 19:09:39 +1000 Subject: [PATCH 264/269] improved SSL debug logging --- .../eclipse/jetty/io/ssl/SslConnection.java | 38 +++++++++---------- .../org/eclipse/jetty/util/BufferUtil.java | 27 +++++++++++++ .../jetty/util/ssl/SslContextFactory.java | 8 ++++ 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index 7ac32a0ef34..243a23e064e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.io.ssl; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; -import java.util.Arrays; import java.util.concurrent.Executor; import javax.net.ssl.SSLEngine; @@ -355,7 +354,7 @@ public class SslConnection extends AbstractConnection synchronized (DecryptedEndPoint.this) { if (DEBUG) - LOG.debug("onIncompleteFlush {}", getEndPoint()); + LOG.debug("onIncompleteFlush {}", SslConnection.this); // If we have pending output data, if (BufferUtil.hasContent(_encryptedOutput)) { @@ -468,8 +467,6 @@ public class SslConnection extends AbstractConnection @Override public synchronized int fill(ByteBuffer buffer) throws IOException { - if (DEBUG) - LOG.debug("{} fill enter", SslConnection.this); try { // Do we already have some decrypted data? @@ -496,8 +493,6 @@ public class SslConnection extends AbstractConnection { // Let's try reading some encrypted data... even if we have some already. int net_filled = getEndPoint().fill(_encryptedInput); - if (DEBUG) - LOG.debug("{} filled {} encrypted bytes", SslConnection.this, net_filled); decryption: while (true) { @@ -507,7 +502,10 @@ public class SslConnection extends AbstractConnection SSLEngineResult unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in); BufferUtil.flipToFlush(app_in, pos); if (DEBUG) - LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult); + { + LOG.debug("{} net={} unwrap {}", SslConnection.this, net_filled, unwrapResult.toString().replace('\n',' ')); + LOG.debug("{} filled {}",SslConnection.this,BufferUtil.toHexSummary(buffer)); + } HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus(); HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus(); @@ -559,8 +557,9 @@ public class SslConnection extends AbstractConnection { _handshaken = true; if (DEBUG) - LOG.debug("{} {} handshake completed", SslConnection.this, - _sslEngine.getUseClientMode() ? "client-side" : "resumed session server-side"); + LOG.debug("{} {} handshook {}/{}", SslConnection.this, + _sslEngine.getUseClientMode() ? "client" : "resumed server", + _sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite()); } // Check whether renegotiation is allowed @@ -661,8 +660,6 @@ public class SslConnection extends AbstractConnection _bufferPool.release(_decryptedInput); _decryptedInput = null; } - if (DEBUG) - LOG.debug("{} fill exit", SslConnection.this); } } @@ -687,10 +684,13 @@ public class SslConnection extends AbstractConnection // will return 0 (even if some handshake bytes were flushed and filled). // it is the applications responsibility to call flush again - either in a busy loop // or better yet by using EndPoint#write to do the flushing. - + if (DEBUG) - LOG.debug("{} flush enter {}", SslConnection.this, Arrays.toString(appOuts)); - int consumed=0; + { + for (ByteBuffer b : appOuts) + LOG.debug("{} flush {}", SslConnection.this, BufferUtil.toHexSummary(b)); + } + try { if (_cannotAcceptMoreAppDataToFlush) @@ -711,10 +711,8 @@ public class SslConnection extends AbstractConnection int pos = BufferUtil.flipToFill(_encryptedOutput); SSLEngineResult wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput); if (DEBUG) - LOG.debug("{} wrap {}", SslConnection.this, wrapResult); + LOG.debug("{} wrap {}", SslConnection.this, wrapResult.toString().replace('\n',' ')); BufferUtil.flipToFlush(_encryptedOutput, pos); - if (wrapResult.bytesConsumed()>0) - consumed+=wrapResult.bytesConsumed(); boolean allConsumed=true; // clear empty buffers to prevent position creeping up the buffer @@ -757,13 +755,13 @@ public class SslConnection extends AbstractConnection default: if (DEBUG) - LOG.debug("{} {} {}", this, wrapResultStatus, BufferUtil.toDetailString(_encryptedOutput)); + LOG.debug("{} wrap {} {}", SslConnection.this, wrapResultStatus, BufferUtil.toHexSummary(_encryptedOutput)); if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED && !_handshaken) { _handshaken = true; if (DEBUG) - LOG.debug("{} {} handshake completed", SslConnection.this, "server-side"); + LOG.debug("{} server handshook complete {}/{}", SslConnection.this, _sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite()); } HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus(); @@ -823,8 +821,6 @@ public class SslConnection extends AbstractConnection } finally { - if (DEBUG) - LOG.debug("{} flush exit, consumed {}", SslConnection.this, consumed); releaseEncryptedOutputBuffer(); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java index 307f44e49d3..97a209c5e25 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java @@ -1020,6 +1020,33 @@ public class BufferUtil else buf.append("\\x").append(TypeUtil.toHexString(b)); } + + + /* ------------------------------------------------------------ */ + /** Convert buffer to a Hex Summary String. + * @param buffer + * @return A string showing the escaped content of the buffer around the + * position and limit (marked with <<< and >>>) + */ + public static String toHexSummary(ByteBuffer buffer) + { + if (buffer == null) + return "null"; + StringBuilder buf = new StringBuilder(); + + buf.append("b[").append(buffer.remaining()).append("]="); + for (int i = buffer.position(); i < buffer.limit(); i++) + { + TypeUtil.toHex(buffer.get(i),buf); + if (i == buffer.position() + 24 && buffer.limit() > buffer.position() + 32) + { + buf.append("..."); + i = buffer.limit() - 8; + } + } + return buf.toString(); + } + private final static int[] decDivisors = {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java index d7300954003..46fe2a56da7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java @@ -224,6 +224,14 @@ public class SslContextFactory extends AbstractLifeCycle public SslContextFactory(boolean trustAll) { setTrustAll(trustAll); + setExcludeCipherSuites( + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); } /** From 87cac64dffad79d1eb1fcc4964374bd774242384 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 10 Sep 2014 10:37:51 +0200 Subject: [PATCH 265/269] Fixed typo, improved logging, removed unused type parameter. --- .../org/eclipse/jetty/io/FillInterest.java | 66 +++++++++---------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java index b2c3f685559..dfc7563c305 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java @@ -27,38 +27,35 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - -/* ------------------------------------------------------------ */ -/** +/** * A Utility class to help implement {@link EndPoint#fillInterested(Callback)} * by keeping state and calling the context and callback objects. - * */ public abstract class FillInterest { private final static Logger LOG = Log.getLogger(FillInterest.class); private final AtomicReference<Callback> _interested = new AtomicReference<>(null); - /* ------------------------------------------------------------ */ protected FillInterest() { } - /* ------------------------------------------------------------ */ - /** Call to register interest in a callback when a read is possible. - * The callback will be called either immediately if {@link #needsFill()} + /** + * Call to register interest in a callback when a read is possible. + * The callback will be called either immediately if {@link #needsFill()} * returns true or eventually once {@link #fillable()} is called. - * @param callback + * + * @param callback the callback to register * @throws ReadPendingException */ - public <C> void register(Callback callback) throws ReadPendingException + public void register(Callback callback) throws ReadPendingException { - if (callback==null) + if (callback == null) throw new IllegalArgumentException(); - - if (!_interested.compareAndSet(null,callback)) + + if (!_interested.compareAndSet(null, callback)) { - LOG.warn("Read pending for "+_interested.get()+" pervented "+callback); + LOG.warn("Read pending for {} prevented {}", _interested, callback); throw new ReadPendingException(); } try @@ -66,70 +63,67 @@ public abstract class FillInterest if (needsFill()) fillable(); } - catch(IOException e) + catch (IOException e) { onFail(e); } } - /* ------------------------------------------------------------ */ - /** Call to signal that a read is now possible. + /** + * Call to signal that a read is now possible. */ public void fillable() { - Callback callback=_interested.get(); - if (callback!=null && _interested.compareAndSet(callback,null)) + Callback callback = _interested.get(); + if (callback != null && _interested.compareAndSet(callback, null)) callback.succeeded(); } - /* ------------------------------------------------------------ */ /** * @return True if a read callback has been registered */ public boolean isInterested() { - return _interested.get()!=null; + return _interested.get() != null; } - /* ------------------------------------------------------------ */ - /** Call to signal a failure to a registered interest + /** + * Call to signal a failure to a registered interest + * * @return true if the cause was passed to a {@link Callback} instance */ public boolean onFail(Throwable cause) { - Callback callback=_interested.get(); - if (callback!=null && _interested.compareAndSet(callback,null)) + Callback callback = _interested.get(); + if (callback != null && _interested.compareAndSet(callback, null)) { callback.failed(cause); return true; } return false; } - - /* ------------------------------------------------------------ */ + public void onClose() { - Callback callback=_interested.get(); - if (callback!=null && _interested.compareAndSet(callback,null)) + Callback callback = _interested.get(); + if (callback != null && _interested.compareAndSet(callback, null)) callback.failed(new ClosedChannelException()); } - - /* ------------------------------------------------------------ */ + @Override public String toString() { - return String.format("FillInterest@%x{%b,%s}",hashCode(),_interested.get(),_interested.get()); + return String.format("FillInterest@%x{%b,%s}", hashCode(), _interested.get(), _interested.get()); } - /* ------------------------------------------------------------ */ - /** Register the read interest + /** + * Register the read interest * Abstract method to be implemented by the Specific ReadInterest to * enquire if a read is immediately possible and if not to schedule a future * call to {@link #fillable()} or {@link #onFail(Throwable)} + * * @return true if a read is possible * @throws IOException */ abstract protected boolean needsFill() throws IOException; - - } From d45a5c861c88e35513b79e97fc56fd3a1fa5731d Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 10 Sep 2014 10:39:15 +0200 Subject: [PATCH 266/269] Introduced factory method to create the SelectorManager instance. --- .../eclipse/jetty/server/ServerConnector.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java index e37b27dacf4..9be3b5b62c1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java @@ -20,10 +20,12 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.nio.channels.Channel; import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.concurrent.Executor; @@ -35,6 +37,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.SelectChannelEndPoint; import org.eclipse.jetty.io.SelectorManager; import org.eclipse.jetty.io.SelectorManager.ManagedSelector; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.Name; @@ -225,11 +228,16 @@ public class ServerConnector extends AbstractNetworkConnector @Name("factories") ConnectionFactory... factories) { super(server,executor,scheduler,bufferPool,acceptors,factories); - _manager = new ServerConnectorManager(getExecutor(), getScheduler(), + _manager = newSelectorManager(getExecutor(), getScheduler(), selectors>0?selectors:Math.max(1,Math.min(4,Runtime.getRuntime().availableProcessors()/2))); addBean(_manager, true); } + protected SelectorManager newSelectorManager(Executor executor, Scheduler scheduler, int selectors) + { + return new ServerConnectorManager(executor, scheduler, selectors); + } + @Override protected void doStart() throws Exception { @@ -480,9 +488,9 @@ public class ServerConnector extends AbstractNetworkConnector _reuseAddress = reuseAddress; } - private final class ServerConnectorManager extends SelectorManager + protected class ServerConnectorManager extends SelectorManager { - private ServerConnectorManager(Executor executor, Scheduler scheduler, int selectors) + public ServerConnectorManager(Executor executor, Scheduler scheduler, int selectors) { super(executor, scheduler, selectors); } @@ -518,7 +526,5 @@ public class ServerConnector extends AbstractNetworkConnector onEndPointClosed(endpoint); super.endPointClosed(endpoint); } - - } } From 1ee11138a7c40741195f1709a000569018e3b39c Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 10 Sep 2014 10:40:59 +0200 Subject: [PATCH 267/269] Introduced field "submitKeyUpdates" instead of relying on a system property. Modified method updateKey() to return a boolean to signal whether the selector was woken up. --- .../org/eclipse/jetty/io/SelectorManager.java | 69 ++++++++++++++----- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index 83b4dcecb11..29e2cd5e8ea 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -58,18 +58,17 @@ import org.eclipse.jetty.util.thread.Scheduler; */ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable { - public static final String SUBMIT_KEY_UPDATES = "org.eclipse.jetty.io.SelectorManager.submitKeyUpdates"; public static final int DEFAULT_CONNECT_TIMEOUT = 15000; protected static final Logger LOG = Log.getLogger(SelectorManager.class); - private final static boolean __submitKeyUpdates = Boolean.valueOf(System.getProperty(SUBMIT_KEY_UPDATES, "false")); - + private final Executor executor; private final Scheduler scheduler; private final ManagedSelector[] _selectors; private long _connectTimeout = DEFAULT_CONNECT_TIMEOUT; - private long _selectorIndex; + private boolean _submitKeyUpdates; private int _priorityDelta; - + private long _selectorIndex; + protected SelectorManager(Executor executor, Scheduler scheduler) { this(executor, scheduler, (Runtime.getRuntime().availableProcessors() + 1) / 2); @@ -149,7 +148,33 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa } } } - + + /** + * @return whether updates to {@link SelectionKey}s are submitted + * to the selector thread or executed by the updater. + * @see #setSubmitKeyUpdates(boolean) + */ + public boolean isSubmitKeyUpdates() + { + return _submitKeyUpdates; + } + + /** + * Controls whether {@link SelectionKey} updates should be submitted for + * execution in the selector thread, or directly executed by the updating + * thread. + * Submission incur is possible queueing and wakeup of the selector, while + * direct execution incurs in lock contention in JDK classes. + * + * @param submitKeyUpdates whether updates to {@link SelectionKey}s are submitted + * to the selector thread or executed by the updater. + * @see SelectorManager.ManagedSelector#updateKey(Runnable) + */ + public void setSubmitKeyUpdates(boolean submitKeyUpdates) + { + _submitKeyUpdates = submitKeyUpdates; + } + /** * Executes the given task in a different thread. * @@ -438,22 +463,29 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa } /** - * Submit a task to update a selector key. If the System property {@link SelectorManager#SUBMIT_KEY_UPDATES} - * is set true (default is false), the task is passed to {@link #submit(Runnable)}. Otherwise it is run immediately and the selector - * woken up if need be. - * @param update the update to a key + * Submits a task to update a {@link SelectionKey}. + * If {@link #isSubmitKeyUpdates()} is true (defaults to false), the + * task is passed to {@link #submit(Runnable)}, otherwise it is executed + * immediately and the selector woken up if need be. + * + * @param update the task that updates the key. + * @return true if the selector was woken up, false otherwise */ - public void updateKey(Runnable update) + public boolean updateKey(Runnable update) { - if (__submitKeyUpdates) + if (isSubmitKeyUpdates()) { - submit(update); + return submit(update); } else { runChange(update); if (_state.compareAndSet(State.SELECT, State.WAKEUP)) - wakeup(); + { + wakeup(); + return true; + } + return false; } } @@ -463,8 +495,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa * (if necessary) to execute the change.</p> * * @param change the change to submit + * @return true if the selector was woken up, false otherwise */ - public void submit(Runnable change) + public boolean submit(Runnable change) { // This method may be called from the selector thread, and therefore // we could directly run the change without queueing, but this may @@ -484,7 +517,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa if (!_state.compareAndSet(State.SELECT, State.WAKEUP)) continue; wakeup(); - break out; + return true; case CHANGES: // Tell the selector thread that we have more changes. // If we fail to CAS, we possibly need to wakeup(), so loop. @@ -504,6 +537,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa throw new IllegalStateException(); } } + + return false; } private void runChanges() @@ -543,7 +578,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa LOG.debug("Starting {} on {}", _thread, this); while (isRunning()) select(); - while(isStopping()) + while (isStopping()) runChanges(); } finally From fd1c9dd8d2c298ba66ae1b3b98bc85719cdefb41 Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Wed, 10 Sep 2014 16:34:25 +0200 Subject: [PATCH 268/269] 443713 - Reduce number of SelectionKey.setInterestOps() calls. Introduced a state machine to handle the various scenarios (ST = selector thread, Tx = pooled thread): ST: call to SCEP.onSelected() moves from SELECTING -> PENDING. ST: call to SCEP.updateKey() moves from PENDING -> UPDATING -> SELECTING T1: call to SCEP.changeInterests() moves (SELECTING | PENDING) -> CHANGING -> SELECTING The race between ST and T1 to move from PENDING to either UPDATING or CHANGING will be won by one thread only, which will then perform the call to SelectionKey.setInterestOps(). Preferably, this will be done by ST during an updateKey() call. If updateKey() has already been invoked, then changeInterests() will perform the call to SelectionKey.setInterestOps(). However, if T1 loses, it still has to perform the key update, so it will spin until ST moves back to SELECTING. --- .../jetty/io/SelectChannelEndPoint.java | 214 +++++++++++++----- .../org/eclipse/jetty/io/SelectorManager.java | 49 +++- 2 files changed, 204 insertions(+), 59 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java index e60c9fa706b..a4dfd83bc2b 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java @@ -22,7 +22,7 @@ import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.io.SelectorManager.ManagedSelector; import org.eclipse.jetty.util.log.Log; @@ -43,27 +43,21 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa { try { - if (getChannel().isOpen()) - { - int oldInterestOps = _key.interestOps(); - int newInterestOps = _interestOps.get(); - if (newInterestOps != oldInterestOps) - setKeyInterests(oldInterestOps, newInterestOps); - } + setKeyInterests(); } catch (CancelledKeyException x) { LOG.debug("Ignoring key update for concurrently closed channel {}", this); close(); } - catch (Exception x) + catch (Throwable x) { LOG.warn("Ignoring key update for " + this, x); close(); } } }; - + private final AtomicReference<State> _interestState = new AtomicReference<>(State.SELECTING); /** * true if {@link ManagedSelector#destroyEndPoint(EndPoint)} has not been called */ @@ -73,11 +67,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa /** * The desired value for {@link SelectionKey#interestOps()} */ - private final AtomicInteger _interestOps = new AtomicInteger(); + private int _interestOps; public SelectChannelEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler, long idleTimeout) { - super(scheduler,channel); + super(scheduler, channel); _selector = selector; _key = key; setIdleTimeout(idleTimeout); @@ -86,78 +80,183 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa @Override protected boolean needsFill() { - updateLocalInterests(SelectionKey.OP_READ, true); - return false; + return !changeInterests(SelectionKey.OP_READ, true); } @Override protected void onIncompleteFlush() { - updateLocalInterests(SelectionKey.OP_WRITE, true); + changeInterests(SelectionKey.OP_WRITE, true); } @Override public void onSelected() { + /** + * This method never runs concurrently with other + * methods that update _interestState. + */ + assert _selector.isSelectorThread(); - int oldInterestOps = _key.interestOps(); + + // Remove the readyOps, that here can only be OP_READ or OP_WRITE (or both). int readyOps = _key.readyOps(); + int oldInterestOps = _interestOps; int newInterestOps = oldInterestOps & ~readyOps; - setKeyInterests(oldInterestOps, newInterestOps); - updateLocalInterests(readyOps, false); - if (_key.isReadable()) + _interestOps = newInterestOps; + + if (!_interestState.compareAndSet(State.SELECTING, State.PENDING)) + throw new IllegalStateException("Invalid state: " + _interestState); + + if (LOG.isDebugEnabled()) + LOG.debug("onSelected {}->{} for {}", oldInterestOps, newInterestOps, this); + + if ((readyOps & SelectionKey.OP_READ) != 0) getFillInterest().fillable(); - if (_key.isWritable()) + if ((readyOps & SelectionKey.OP_WRITE) != 0) getWriteFlusher().completeWrite(); } - - private void updateLocalInterests(int operation, boolean add) + @Override + public void updateKey() { + /** + * This method may run concurrently with {@link #changeInterests(int, boolean)}. + */ + + assert _selector.isSelectorThread(); + while (true) { - int oldInterestOps = _interestOps.get(); - int newInterestOps; - if (add) - newInterestOps = oldInterestOps | operation; - else - newInterestOps = oldInterestOps & ~operation; - - if (isInputShutdown()) - newInterestOps &= ~SelectionKey.OP_READ; - if (isOutputShutdown()) - newInterestOps &= ~SelectionKey.OP_WRITE; - - if (newInterestOps != oldInterestOps) + State current = _interestState.get(); + switch (current) { - if (_interestOps.compareAndSet(oldInterestOps, newInterestOps)) + case SELECTING: { - if (LOG.isDebugEnabled()) - LOG.debug("Local interests updated {} -> {} for {}", oldInterestOps, newInterestOps, this); - _selector.updateKey(_updateTask); + // When a whole cycle triggered by changeInterests() + // happens, we finish the job by updating the key. + setKeyInterests(); + return; } - else + case PENDING: { - if (LOG.isDebugEnabled()) - LOG.debug("Local interests update conflict: now {}, was {}, attempted {} for {}", _interestOps.get(), oldInterestOps, newInterestOps, this); - continue; + if (!_interestState.compareAndSet(current, State.UPDATING)) + continue; + break; + } + case UPDATING: + { + // Set the key interest as expected. + setKeyInterests(); + if (!_interestState.compareAndSet(current, State.SELECTING)) + throw new IllegalStateException(); + return; + } + case CHANGING: + { + // We lost the race to update _interestOps, + // let changeInterests() perform the update. + return; + } + default: + { + throw new IllegalStateException(); } } - else - { - if (LOG.isDebugEnabled()) - LOG.debug("Ignoring local interests update {} -> {} for {}", oldInterestOps, newInterestOps, this); - } - break; } } - - private void setKeyInterests(int oldInterestOps, int newInterestOps) + private boolean changeInterests(int operation, boolean add) { + /** + * This method may run concurrently with {@link #updateKey()}. + */ + + boolean pending = false; + boolean changed = true; + while (true) + { + State current = _interestState.get(); + switch (current) + { + case SELECTING: + case PENDING: + { + if (!_interestState.compareAndSet(current, State.CHANGING)) + continue; + pending = current == State.PENDING; + break; + } + case UPDATING: + { + // We lost the race to update _interestOps, but we + // must update it nonetheless, so yield and spin, + // waiting for the state to be SELECTING again. + Thread.yield(); + break; + } + case CHANGING: + { + int oldInterestOps = _interestOps; + int newInterestOps; + if (add) + newInterestOps = oldInterestOps | operation; + else + newInterestOps = oldInterestOps & ~operation; + + if (isInputShutdown()) + { + newInterestOps &= ~SelectionKey.OP_READ; + if (add && (operation & SelectionKey.OP_READ) != 0) + changed = false; + } + + if (isOutputShutdown()) + { + newInterestOps &= ~SelectionKey.OP_WRITE; + if (add && (operation & SelectionKey.OP_WRITE) != 0) + changed = false; + } + + if (LOG.isDebugEnabled()) + LOG.debug("changeInterests pending={} {}->{} for {}", pending, oldInterestOps, newInterestOps, this); + + if (newInterestOps != oldInterestOps) + _interestOps = newInterestOps; + + if (!_interestState.compareAndSet(current, State.SELECTING)) + throw new IllegalStateException("Invalid state: " + current); + + // We only update the key if updateKey() does not do it for us, + // because doing it from the selector thread is less expensive. + // This must be done after CASing the state above, otherwise the + // selector may select and call onSelected() concurrently. + submitKeyUpdate(!pending); + + return changed; + } + default: + { + throw new IllegalStateException(); + } + } + } + } + + protected void submitKeyUpdate(boolean submit) + { + if (submit) + _selector.updateKey(_updateTask); + } + + private void setKeyInterests() + { + int oldInterestOps = _key.interestOps(); + int newInterestOps = _interestOps; if (LOG.isDebugEnabled()) - LOG.debug("Key interests updated {} -> {}", oldInterestOps, newInterestOps); - _key.interestOps(newInterestOps); + LOG.debug("Key interests update {} -> {}", oldInterestOps, newInterestOps); + if (oldInterestOps != newInterestOps) + _key.interestOps(newInterestOps); } @Override @@ -199,13 +298,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa int keyReadiness = valid ? _key.readyOps() : -1; return String.format("%s{io=%d,kio=%d,kro=%d}", super.toString(), - _interestOps.get(), + _interestOps, keyInterests, keyReadiness); } catch (CancelledKeyException x) { - return String.format("%s{io=%s,kio=-2,kro=-2}", super.toString(), _interestOps.get()); + return String.format("%s{io=%s,kio=-2,kro=-2}", super.toString(), _interestOps); } } + + private enum State + { + SELECTING, PENDING, UPDATING, CHANGING + } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index 29e2cd5e8ea..c457c35a4e4 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -650,6 +650,17 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa ((EndPoint)attachment).close(); } } + + // Allow any dispatched tasks to run. + Thread.yield(); + + // Update the keys. + for (SelectionKey key : selectedKeys) + { + if (key.isValid()) + updateKey(key); + } + selectedKeys.clear(); } catch (Throwable x) @@ -697,6 +708,30 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa } } + private void updateKey(SelectionKey key) + { + Object attachment = key.attachment(); + try + { + if (attachment instanceof SelectableEndPoint) + { + ((SelectableEndPoint)attachment).updateKey(); + } + } + catch (CancelledKeyException x) + { + LOG.debug("Ignoring cancelled key for channel {}", key.channel()); + if (attachment instanceof EndPoint) + closeNoExceptions((EndPoint)attachment); + } + catch (Throwable x) + { + LOG.warn("Could not process key for channel " + key.channel(), x); + if (attachment instanceof EndPoint) + closeNoExceptions((EndPoint)attachment); + } + } + private void processConnect(SelectionKey key, Connect connect) { SocketChannel channel = (SocketChannel)key.channel(); @@ -1075,15 +1110,21 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa } /** - * A {@link SelectableEndPoint} is an {@link EndPoint} that wish to be notified of - * non-blocking events by the {@link ManagedSelector}. + * A {@link SelectableEndPoint} is an {@link EndPoint} that wish to be + * notified of non-blocking events by the {@link ManagedSelector}. */ public interface SelectableEndPoint extends EndPoint { /** - * <p>Callback method invoked when a read or write events has been detected by the {@link ManagedSelector} - * for this endpoint.</p> + * Callback method invoked when a read or write events has been + * detected by the {@link ManagedSelector} for this endpoint. */ void onSelected(); + + /** + * Callback method invoked when all the keys selected by the + * {@link ManagedSelector} for this endpoint have been processed. + */ + void updateKey(); } } From 15781da7557f73d76935e1e5734c45c2a469b17c Mon Sep 17 00:00:00 2001 From: Simone Bordet <simone.bordet@gmail.com> Date: Thu, 11 Sep 2014 00:33:47 +0200 Subject: [PATCH 269/269] Fixed spinning loop that called onFillable() in case of closed connection. --- .../src/main/java/org/eclipse/jetty/server/HttpConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 39ee045cfd0..e942b9daa00 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -266,7 +266,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http finally { setCurrentConnection(last); - if (!suspended && getEndPoint().isOpen() && getEndPoint().getConnection()==this) + if (!suspended && !getEndPoint().isInputShutdown() && getEndPoint().getConnection()==this) { fillInterested(); }